Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer updates from Thomas Gleixner: "The timer departement delivers: - more year 2038 rework - a massive rework of the arm achitected timer - preparatory patches to allow NTP correction of clock event devices to avoid early expiry - the usual pile of fixes and enhancements all over the place" * 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (91 commits) timer/sysclt: Restrict timer migration sysctl values to 0 and 1 arm64/arch_timer: Mark errata handlers as __maybe_unused Clocksource/mips-gic: Remove redundant non devicetree init MIPS/Malta: Probe gic-timer via devicetree clocksource: Use GENMASK_ULL in definition of CLOCKSOURCE_MASK acpi/arm64: Add SBSA Generic Watchdog support in GTDT driver clocksource: arm_arch_timer: add GTDT support for memory-mapped timer acpi/arm64: Add memory-mapped timer support in GTDT driver clocksource: arm_arch_timer: simplify ACPI support code. acpi/arm64: Add GTDT table parse driver clocksource: arm_arch_timer: split MMIO timer probing. clocksource: arm_arch_timer: add structs to describe MMIO timer clocksource: arm_arch_timer: move arch_timer_needs_of_probing into DT init call clocksource: arm_arch_timer: refactor arch_timer_needs_probing clocksource: arm_arch_timer: split dt-only rate handling x86/uv/time: Set ->min_delta_ticks and ->max_delta_ticks unicore32/time: Set ->min_delta_ticks and ->max_delta_ticks um/time: Set ->min_delta_ticks and ->max_delta_ticks tile/time: Set ->min_delta_ticks and ->max_delta_ticks score/time: Set ->min_delta_ticks and ->max_delta_ticks ...
This commit is contained in:
commit
174ddfd5df
@ -54,6 +54,7 @@ stable kernels.
|
|||||||
| ARM | Cortex-A57 | #852523 | N/A |
|
| ARM | Cortex-A57 | #852523 | N/A |
|
||||||
| ARM | Cortex-A57 | #834220 | ARM64_ERRATUM_834220 |
|
| ARM | Cortex-A57 | #834220 | ARM64_ERRATUM_834220 |
|
||||||
| ARM | Cortex-A72 | #853709 | N/A |
|
| ARM | Cortex-A72 | #853709 | N/A |
|
||||||
|
| ARM | Cortex-A73 | #858921 | ARM64_ERRATUM_858921 |
|
||||||
| ARM | MMU-500 | #841119,#826419 | N/A |
|
| ARM | MMU-500 | #841119,#826419 | N/A |
|
||||||
| | | | |
|
| | | | |
|
||||||
| Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 |
|
| Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 |
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
Cortina Systems Gemini timer
|
|
||||||
|
|
||||||
This timer is embedded in the Cortina Systems Gemini SoCs.
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
|
|
||||||
- compatible : Must be "cortina,gemini-timer"
|
|
||||||
- reg : Should contain registers location and length
|
|
||||||
- interrupts : Should contain the three timer interrupts with
|
|
||||||
flags for rising edge
|
|
||||||
- syscon : a phandle to the global Gemini system controller
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
timer@43000000 {
|
|
||||||
compatible = "cortina,gemini-timer";
|
|
||||||
reg = <0x43000000 0x1000>;
|
|
||||||
interrupts = <14 IRQ_TYPE_EDGE_RISING>, /* Timer 1 */
|
|
||||||
<15 IRQ_TYPE_EDGE_RISING>, /* Timer 2 */
|
|
||||||
<16 IRQ_TYPE_EDGE_RISING>; /* Timer 3 */
|
|
||||||
syscon = <&syscon>;
|
|
||||||
};
|
|
33
Documentation/devicetree/bindings/timer/faraday,fttmr010.txt
Normal file
33
Documentation/devicetree/bindings/timer/faraday,fttmr010.txt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
Faraday Technology timer
|
||||||
|
|
||||||
|
This timer is a generic IP block from Faraday Technology, embedded in the
|
||||||
|
Cortina Systems Gemini SoCs and other designs.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- compatible : Must be one of
|
||||||
|
"faraday,fttmr010"
|
||||||
|
"cortina,gemini-timer"
|
||||||
|
- reg : Should contain registers location and length
|
||||||
|
- interrupts : Should contain the three timer interrupts usually with
|
||||||
|
flags for falling edge
|
||||||
|
|
||||||
|
Optionally required properties:
|
||||||
|
|
||||||
|
- clocks : a clock to provide the tick rate for "faraday,fttmr010"
|
||||||
|
- clock-names : should be "EXTCLK" and "PCLK" for the external tick timer
|
||||||
|
and peripheral clock respectively, for "faraday,fttmr010"
|
||||||
|
- syscon : a phandle to the global Gemini system controller if the compatible
|
||||||
|
type is "cortina,gemini-timer"
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
timer@43000000 {
|
||||||
|
compatible = "faraday,fttmr010";
|
||||||
|
reg = <0x43000000 0x1000>;
|
||||||
|
interrupts = <14 IRQ_TYPE_EDGE_FALLING>, /* Timer 1 */
|
||||||
|
<15 IRQ_TYPE_EDGE_FALLING>, /* Timer 2 */
|
||||||
|
<16 IRQ_TYPE_EDGE_FALLING>; /* Timer 3 */
|
||||||
|
clocks = <&extclk>, <&pclk>;
|
||||||
|
clock-names = "EXTCLK", "PCLK";
|
||||||
|
};
|
@ -1,9 +1,15 @@
|
|||||||
Rockchip rk timer
|
Rockchip rk timer
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: shall be one of:
|
- compatible: should be:
|
||||||
"rockchip,rk3288-timer" - for rk3066, rk3036, rk3188, rk322x, rk3288, rk3368
|
"rockchip,rk3036-timer", "rockchip,rk3288-timer": for Rockchip RK3036
|
||||||
"rockchip,rk3399-timer" - for rk3399
|
"rockchip,rk3066-timer", "rockchip,rk3288-timer": for Rockchip RK3066
|
||||||
|
"rockchip,rk3188-timer", "rockchip,rk3288-timer": for Rockchip RK3188
|
||||||
|
"rockchip,rk3228-timer", "rockchip,rk3288-timer": for Rockchip RK3228
|
||||||
|
"rockchip,rk3229-timer", "rockchip,rk3288-timer": for Rockchip RK3229
|
||||||
|
"rockchip,rk3288-timer": for Rockchip RK3288
|
||||||
|
"rockchip,rk3368-timer", "rockchip,rk3288-timer": for Rockchip RK3368
|
||||||
|
"rockchip,rk3399-timer": for Rockchip RK3399
|
||||||
- reg: base address of the timer register starting with TIMERS CONTROL register
|
- reg: base address of the timer register starting with TIMERS CONTROL register
|
||||||
- interrupts: should contain the interrupts for Timer0
|
- interrupts: should contain the interrupts for Timer0
|
||||||
- clocks : must contain an entry for each entry in clock-names
|
- clocks : must contain an entry for each entry in clock-names
|
||||||
|
@ -11119,6 +11119,7 @@ F: drivers/power/supply/bq27xxx_battery_i2c.c
|
|||||||
TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
|
TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
|
||||||
M: John Stultz <john.stultz@linaro.org>
|
M: John Stultz <john.stultz@linaro.org>
|
||||||
M: Thomas Gleixner <tglx@linutronix.de>
|
M: Thomas Gleixner <tglx@linutronix.de>
|
||||||
|
R: Stephen Boyd <sboyd@codeaurora.org>
|
||||||
L: linux-kernel@vger.kernel.org
|
L: linux-kernel@vger.kernel.org
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
|
||||||
S: Supported
|
S: Supported
|
||||||
|
@ -1016,6 +1016,7 @@ SYSCALL_DEFINE2(osf_gettimeofday, struct timeval32 __user *, tv,
|
|||||||
SYSCALL_DEFINE2(osf_settimeofday, struct timeval32 __user *, tv,
|
SYSCALL_DEFINE2(osf_settimeofday, struct timeval32 __user *, tv,
|
||||||
struct timezone __user *, tz)
|
struct timezone __user *, tz)
|
||||||
{
|
{
|
||||||
|
struct timespec64 kts64;
|
||||||
struct timespec kts;
|
struct timespec kts;
|
||||||
struct timezone ktz;
|
struct timezone ktz;
|
||||||
|
|
||||||
@ -1023,13 +1024,14 @@ SYSCALL_DEFINE2(osf_settimeofday, struct timeval32 __user *, tv,
|
|||||||
if (get_tv32((struct timeval *)&kts, tv))
|
if (get_tv32((struct timeval *)&kts, tv))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
kts.tv_nsec *= 1000;
|
kts.tv_nsec *= 1000;
|
||||||
|
kts64 = timespec_to_timespec64(kts);
|
||||||
}
|
}
|
||||||
if (tz) {
|
if (tz) {
|
||||||
if (copy_from_user(&ktz, tz, sizeof(*tz)))
|
if (copy_from_user(&ktz, tz, sizeof(*tz)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
|
return do_sys_settimeofday64(tv ? &kts64 : NULL, tz ? &ktz : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys_ni_posix_timers(void);
|
asmlinkage long sys_ni_posix_timers(void);
|
||||||
|
@ -106,6 +106,22 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
timer3: timer@2000e000 {
|
||||||
|
compatible = "rockchip,rk3188-timer", "rockchip,rk3288-timer";
|
||||||
|
reg = <0x2000e000 0x20>;
|
||||||
|
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
clocks = <&cru SCLK_TIMER3>, <&cru PCLK_TIMER3>;
|
||||||
|
clock-names = "timer", "pclk";
|
||||||
|
};
|
||||||
|
|
||||||
|
timer6: timer@200380a0 {
|
||||||
|
compatible = "rockchip,rk3188-timer", "rockchip,rk3288-timer";
|
||||||
|
reg = <0x200380a0 0x20>;
|
||||||
|
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
clocks = <&cru SCLK_TIMER6>, <&cru PCLK_TIMER0>;
|
||||||
|
clock-names = "timer", "pclk";
|
||||||
|
};
|
||||||
|
|
||||||
i2s0: i2s@1011a000 {
|
i2s0: i2s@1011a000 {
|
||||||
compatible = "rockchip,rk3188-i2s", "rockchip,rk3066-i2s";
|
compatible = "rockchip,rk3188-i2s", "rockchip,rk3066-i2s";
|
||||||
reg = <0x1011a000 0x2000>;
|
reg = <0x1011a000 0x2000>;
|
||||||
@ -530,6 +546,7 @@
|
|||||||
|
|
||||||
&global_timer {
|
&global_timer {
|
||||||
interrupts = <GIC_PPI 11 0xf04>;
|
interrupts = <GIC_PPI 11 0xf04>;
|
||||||
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
&local_timer {
|
&local_timer {
|
||||||
|
@ -325,7 +325,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
timer: timer@110c0000 {
|
timer: timer@110c0000 {
|
||||||
compatible = "rockchip,rk3288-timer";
|
compatible = "rockchip,rk3228-timer", "rockchip,rk3288-timer";
|
||||||
reg = <0x110c0000 0x20>;
|
reg = <0x110c0000 0x20>;
|
||||||
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
clocks = <&xin24m>, <&cru PCLK_TIMER>;
|
clocks = <&xin24m>, <&cru PCLK_TIMER>;
|
||||||
|
@ -2,6 +2,7 @@ config ARM64
|
|||||||
def_bool y
|
def_bool y
|
||||||
select ACPI_CCA_REQUIRED if ACPI
|
select ACPI_CCA_REQUIRED if ACPI
|
||||||
select ACPI_GENERIC_GSI if ACPI
|
select ACPI_GENERIC_GSI if ACPI
|
||||||
|
select ACPI_GTDT if ACPI
|
||||||
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
|
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
|
||||||
select ACPI_MCFG if ACPI
|
select ACPI_MCFG if ACPI
|
||||||
select ACPI_SPCR_TABLE if ACPI
|
select ACPI_SPCR_TABLE if ACPI
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <linux/bug.h>
|
#include <linux/bug.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/jump_label.h>
|
#include <linux/jump_label.h>
|
||||||
|
#include <linux/smp.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#include <clocksource/arm_arch_timer.h>
|
#include <clocksource/arm_arch_timer.h>
|
||||||
@ -37,24 +38,44 @@ extern struct static_key_false arch_timer_read_ool_enabled;
|
|||||||
#define needs_unstable_timer_counter_workaround() false
|
#define needs_unstable_timer_counter_workaround() false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum arch_timer_erratum_match_type {
|
||||||
|
ate_match_dt,
|
||||||
|
ate_match_local_cap_id,
|
||||||
|
ate_match_acpi_oem_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct clock_event_device;
|
||||||
|
|
||||||
struct arch_timer_erratum_workaround {
|
struct arch_timer_erratum_workaround {
|
||||||
const char *id; /* Indicate the Erratum ID */
|
enum arch_timer_erratum_match_type match_type;
|
||||||
|
const void *id;
|
||||||
|
const char *desc;
|
||||||
u32 (*read_cntp_tval_el0)(void);
|
u32 (*read_cntp_tval_el0)(void);
|
||||||
u32 (*read_cntv_tval_el0)(void);
|
u32 (*read_cntv_tval_el0)(void);
|
||||||
u64 (*read_cntvct_el0)(void);
|
u64 (*read_cntvct_el0)(void);
|
||||||
|
int (*set_next_event_phys)(unsigned long, struct clock_event_device *);
|
||||||
|
int (*set_next_event_virt)(unsigned long, struct clock_event_device *);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround;
|
DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *,
|
||||||
|
timer_unstable_counter_workaround);
|
||||||
|
|
||||||
#define arch_timer_reg_read_stable(reg) \
|
#define arch_timer_reg_read_stable(reg) \
|
||||||
({ \
|
({ \
|
||||||
u64 _val; \
|
u64 _val; \
|
||||||
if (needs_unstable_timer_counter_workaround()) \
|
if (needs_unstable_timer_counter_workaround()) { \
|
||||||
_val = timer_unstable_counter_workaround->read_##reg();\
|
const struct arch_timer_erratum_workaround *wa; \
|
||||||
else \
|
preempt_disable(); \
|
||||||
_val = read_sysreg(reg); \
|
wa = __this_cpu_read(timer_unstable_counter_workaround); \
|
||||||
_val; \
|
if (wa && wa->read_##reg) \
|
||||||
|
_val = wa->read_##reg(); \
|
||||||
|
else \
|
||||||
|
_val = read_sysreg(reg); \
|
||||||
|
preempt_enable(); \
|
||||||
|
} else { \
|
||||||
|
_val = read_sysreg(reg); \
|
||||||
|
} \
|
||||||
|
_val; \
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -37,7 +37,8 @@
|
|||||||
#define ARM64_HAS_NO_FPSIMD 16
|
#define ARM64_HAS_NO_FPSIMD 16
|
||||||
#define ARM64_WORKAROUND_REPEAT_TLBI 17
|
#define ARM64_WORKAROUND_REPEAT_TLBI 17
|
||||||
#define ARM64_WORKAROUND_QCOM_FALKOR_E1003 18
|
#define ARM64_WORKAROUND_QCOM_FALKOR_E1003 18
|
||||||
|
#define ARM64_WORKAROUND_858921 19
|
||||||
|
|
||||||
#define ARM64_NCAPS 19
|
#define ARM64_NCAPS 20
|
||||||
|
|
||||||
#endif /* __ASM_CPUCAPS_H */
|
#endif /* __ASM_CPUCAPS_H */
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
#define ARM_CPU_PART_FOUNDATION 0xD00
|
#define ARM_CPU_PART_FOUNDATION 0xD00
|
||||||
#define ARM_CPU_PART_CORTEX_A57 0xD07
|
#define ARM_CPU_PART_CORTEX_A57 0xD07
|
||||||
#define ARM_CPU_PART_CORTEX_A53 0xD03
|
#define ARM_CPU_PART_CORTEX_A53 0xD03
|
||||||
|
#define ARM_CPU_PART_CORTEX_A73 0xD09
|
||||||
|
|
||||||
#define APM_CPU_PART_POTENZA 0x000
|
#define APM_CPU_PART_POTENZA 0x000
|
||||||
|
|
||||||
@ -92,6 +93,7 @@
|
|||||||
|
|
||||||
#define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
|
#define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
|
||||||
#define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
|
#define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
|
||||||
|
#define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
|
||||||
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
|
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
|
||||||
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
|
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
|
||||||
#define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1)
|
#define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1)
|
||||||
|
@ -175,6 +175,8 @@
|
|||||||
#define ESR_ELx_SYS64_ISS_SYS_CTR_READ (ESR_ELx_SYS64_ISS_SYS_CTR | \
|
#define ESR_ELx_SYS64_ISS_SYS_CTR_READ (ESR_ELx_SYS64_ISS_SYS_CTR | \
|
||||||
ESR_ELx_SYS64_ISS_DIR_READ)
|
ESR_ELx_SYS64_ISS_DIR_READ)
|
||||||
|
|
||||||
|
#define ESR_ELx_SYS64_ISS_SYS_CNTVCT (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 2, 14, 0) | \
|
||||||
|
ESR_ELx_SYS64_ISS_DIR_READ)
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
|
|
||||||
|
@ -53,6 +53,13 @@ static int cpu_enable_trap_ctr_access(void *__unused)
|
|||||||
.midr_range_min = min, \
|
.midr_range_min = min, \
|
||||||
.midr_range_max = max
|
.midr_range_max = max
|
||||||
|
|
||||||
|
#define MIDR_ALL_VERSIONS(model) \
|
||||||
|
.def_scope = SCOPE_LOCAL_CPU, \
|
||||||
|
.matches = is_affected_midr_range, \
|
||||||
|
.midr_model = model, \
|
||||||
|
.midr_range_min = 0, \
|
||||||
|
.midr_range_max = (MIDR_VARIANT_MASK | MIDR_REVISION_MASK)
|
||||||
|
|
||||||
const struct arm64_cpu_capabilities arm64_errata[] = {
|
const struct arm64_cpu_capabilities arm64_errata[] = {
|
||||||
#if defined(CONFIG_ARM64_ERRATUM_826319) || \
|
#if defined(CONFIG_ARM64_ERRATUM_826319) || \
|
||||||
defined(CONFIG_ARM64_ERRATUM_827319) || \
|
defined(CONFIG_ARM64_ERRATUM_827319) || \
|
||||||
@ -150,6 +157,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
|
|||||||
MIDR_CPU_VAR_REV(0, 0),
|
MIDR_CPU_VAR_REV(0, 0),
|
||||||
MIDR_CPU_VAR_REV(0, 0)),
|
MIDR_CPU_VAR_REV(0, 0)),
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_ARM64_ERRATUM_858921
|
||||||
|
{
|
||||||
|
/* Cortex-A73 all versions */
|
||||||
|
.desc = "ARM erratum 858921",
|
||||||
|
.capability = ARM64_WORKAROUND_858921,
|
||||||
|
MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
|
||||||
|
},
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -1090,20 +1090,29 @@ static void __init setup_feature_capabilities(void)
|
|||||||
* Check if the current CPU has a given feature capability.
|
* Check if the current CPU has a given feature capability.
|
||||||
* Should be called from non-preemptible context.
|
* Should be called from non-preemptible context.
|
||||||
*/
|
*/
|
||||||
bool this_cpu_has_cap(unsigned int cap)
|
static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array,
|
||||||
|
unsigned int cap)
|
||||||
{
|
{
|
||||||
const struct arm64_cpu_capabilities *caps;
|
const struct arm64_cpu_capabilities *caps;
|
||||||
|
|
||||||
if (WARN_ON(preemptible()))
|
if (WARN_ON(preemptible()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (caps = arm64_features; caps->desc; caps++)
|
for (caps = cap_array; caps->desc; caps++)
|
||||||
if (caps->capability == cap && caps->matches)
|
if (caps->capability == cap && caps->matches)
|
||||||
return caps->matches(caps, SCOPE_LOCAL_CPU);
|
return caps->matches(caps, SCOPE_LOCAL_CPU);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern const struct arm64_cpu_capabilities arm64_errata[];
|
||||||
|
|
||||||
|
bool this_cpu_has_cap(unsigned int cap)
|
||||||
|
{
|
||||||
|
return (__this_cpu_has_cap(arm64_features, cap) ||
|
||||||
|
__this_cpu_has_cap(arm64_errata, cap));
|
||||||
|
}
|
||||||
|
|
||||||
void __init setup_cpu_features(void)
|
void __init setup_cpu_features(void)
|
||||||
{
|
{
|
||||||
u32 cwg;
|
u32 cwg;
|
||||||
|
@ -505,6 +505,14 @@ static void ctr_read_handler(unsigned int esr, struct pt_regs *regs)
|
|||||||
regs->pc += 4;
|
regs->pc += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT;
|
||||||
|
|
||||||
|
pt_regs_write_reg(regs, rt, arch_counter_get_cntvct());
|
||||||
|
regs->pc += 4;
|
||||||
|
}
|
||||||
|
|
||||||
struct sys64_hook {
|
struct sys64_hook {
|
||||||
unsigned int esr_mask;
|
unsigned int esr_mask;
|
||||||
unsigned int esr_val;
|
unsigned int esr_val;
|
||||||
@ -523,6 +531,12 @@ static struct sys64_hook sys64_hooks[] = {
|
|||||||
.esr_val = ESR_ELx_SYS64_ISS_SYS_CTR_READ,
|
.esr_val = ESR_ELx_SYS64_ISS_SYS_CTR_READ,
|
||||||
.handler = ctr_read_handler,
|
.handler = ctr_read_handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
/* Trap read access to CNTVCT_EL0 */
|
||||||
|
.esr_mask = ESR_ELx_SYS64_ISS_SYS_OP_MASK,
|
||||||
|
.esr_val = ESR_ELx_SYS64_ISS_SYS_CNTVCT,
|
||||||
|
.handler = cntvct_read_handler,
|
||||||
|
},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -230,7 +230,9 @@ static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt)
|
|||||||
clock_tick = get_sclk();
|
clock_tick = get_sclk();
|
||||||
evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
|
evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
|
||||||
evt->max_delta_ns = clockevent_delta2ns(-1, evt);
|
evt->max_delta_ns = clockevent_delta2ns(-1, evt);
|
||||||
|
evt->max_delta_ticks = (unsigned long)-1;
|
||||||
evt->min_delta_ns = clockevent_delta2ns(100, evt);
|
evt->min_delta_ns = clockevent_delta2ns(100, evt);
|
||||||
|
evt->min_delta_ticks = 100;
|
||||||
|
|
||||||
evt->cpumask = cpumask_of(0);
|
evt->cpumask = cpumask_of(0);
|
||||||
|
|
||||||
@ -344,7 +346,9 @@ void bfin_coretmr_clockevent_init(void)
|
|||||||
clock_tick = get_cclk() / TIME_SCALE;
|
clock_tick = get_cclk() / TIME_SCALE;
|
||||||
evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
|
evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
|
||||||
evt->max_delta_ns = clockevent_delta2ns(-1, evt);
|
evt->max_delta_ns = clockevent_delta2ns(-1, evt);
|
||||||
|
evt->max_delta_ticks = (unsigned long)-1;
|
||||||
evt->min_delta_ns = clockevent_delta2ns(100, evt);
|
evt->min_delta_ns = clockevent_delta2ns(100, evt);
|
||||||
|
evt->min_delta_ticks = 100;
|
||||||
|
|
||||||
evt->cpumask = cpumask_of(cpu);
|
evt->cpumask = cpumask_of(cpu);
|
||||||
|
|
||||||
|
@ -234,7 +234,9 @@ void __init timer64_init(void)
|
|||||||
clockevents_calc_mult_shift(cd, c6x_core_freq / TIMER_DIVISOR, 5);
|
clockevents_calc_mult_shift(cd, c6x_core_freq / TIMER_DIVISOR, 5);
|
||||||
|
|
||||||
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
|
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
|
||||||
|
cd->max_delta_ticks = 0x7fffffff;
|
||||||
cd->min_delta_ns = clockevent_delta2ns(250, cd);
|
cd->min_delta_ns = clockevent_delta2ns(250, cd);
|
||||||
|
cd->min_delta_ticks = 250;
|
||||||
|
|
||||||
cd->cpumask = cpumask_of(smp_processor_id());
|
cd->cpumask = cpumask_of(smp_processor_id());
|
||||||
|
|
||||||
|
@ -199,7 +199,9 @@ void __init time_init_deferred(void)
|
|||||||
clockevents_calc_mult_shift(ce_dev, sleep_clk_freq, 4);
|
clockevents_calc_mult_shift(ce_dev, sleep_clk_freq, 4);
|
||||||
|
|
||||||
ce_dev->max_delta_ns = clockevent_delta2ns(0x7fffffff, ce_dev);
|
ce_dev->max_delta_ns = clockevent_delta2ns(0x7fffffff, ce_dev);
|
||||||
|
ce_dev->max_delta_ticks = 0x7fffffff;
|
||||||
ce_dev->min_delta_ns = clockevent_delta2ns(0xf, ce_dev);
|
ce_dev->min_delta_ns = clockevent_delta2ns(0xf, ce_dev);
|
||||||
|
ce_dev->min_delta_ticks = 0xf;
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
setup_percpu_clockdev();
|
setup_percpu_clockdev();
|
||||||
|
@ -149,8 +149,10 @@ void hw_timer_init(irq_handler_t handler)
|
|||||||
cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
|
cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
|
||||||
cf_pit_clockevent.max_delta_ns =
|
cf_pit_clockevent.max_delta_ns =
|
||||||
clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
|
clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
|
||||||
|
cf_pit_clockevent.max_delta_ticks = 0xFFFF;
|
||||||
cf_pit_clockevent.min_delta_ns =
|
cf_pit_clockevent.min_delta_ns =
|
||||||
clockevent_delta2ns(0x3f, &cf_pit_clockevent);
|
clockevent_delta2ns(0x3f, &cf_pit_clockevent);
|
||||||
|
cf_pit_clockevent.min_delta_ticks = 0x3f;
|
||||||
clockevents_register_device(&cf_pit_clockevent);
|
clockevents_register_device(&cf_pit_clockevent);
|
||||||
|
|
||||||
setup_irq(MCF_IRQ_PIT1, &pit_irq);
|
setup_irq(MCF_IRQ_PIT1, &pit_irq);
|
||||||
|
@ -138,7 +138,9 @@ static int __init alchemy_time_init(unsigned int m2int)
|
|||||||
cd->shift = 32;
|
cd->shift = 32;
|
||||||
cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift);
|
cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift);
|
||||||
cd->max_delta_ns = clockevent_delta2ns(0xffffffff, cd);
|
cd->max_delta_ns = clockevent_delta2ns(0xffffffff, cd);
|
||||||
cd->min_delta_ns = clockevent_delta2ns(9, cd); /* ~0.28ms */
|
cd->max_delta_ticks = 0xffffffff;
|
||||||
|
cd->min_delta_ns = clockevent_delta2ns(9, cd);
|
||||||
|
cd->min_delta_ticks = 9; /* ~0.28ms */
|
||||||
clockevents_register_device(cd);
|
clockevents_register_device(cd);
|
||||||
setup_irq(m2int, &au1x_rtcmatch2_irqaction);
|
setup_irq(m2int, &au1x_rtcmatch2_irqaction);
|
||||||
|
|
||||||
|
@ -145,7 +145,9 @@ void __init plat_time_init(void)
|
|||||||
|
|
||||||
clockevent_set_clock(&jz4740_clockevent, clk_rate);
|
clockevent_set_clock(&jz4740_clockevent, clk_rate);
|
||||||
jz4740_clockevent.min_delta_ns = clockevent_delta2ns(100, &jz4740_clockevent);
|
jz4740_clockevent.min_delta_ns = clockevent_delta2ns(100, &jz4740_clockevent);
|
||||||
|
jz4740_clockevent.min_delta_ticks = 100;
|
||||||
jz4740_clockevent.max_delta_ns = clockevent_delta2ns(0xffff, &jz4740_clockevent);
|
jz4740_clockevent.max_delta_ns = clockevent_delta2ns(0xffff, &jz4740_clockevent);
|
||||||
|
jz4740_clockevent.max_delta_ticks = 0xffff;
|
||||||
jz4740_clockevent.cpumask = cpumask_of(0);
|
jz4740_clockevent.cpumask = cpumask_of(0);
|
||||||
|
|
||||||
clockevents_register_device(&jz4740_clockevent);
|
clockevents_register_device(&jz4740_clockevent);
|
||||||
|
@ -123,7 +123,9 @@ void sb1480_clockevent_init(void)
|
|||||||
CLOCK_EVT_FEAT_ONESHOT;
|
CLOCK_EVT_FEAT_ONESHOT;
|
||||||
clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
|
clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
|
||||||
cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd);
|
cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd);
|
||||||
|
cd->max_delta_ticks = 0x7fffff;
|
||||||
cd->min_delta_ns = clockevent_delta2ns(2, cd);
|
cd->min_delta_ns = clockevent_delta2ns(2, cd);
|
||||||
|
cd->min_delta_ticks = 2;
|
||||||
cd->rating = 200;
|
cd->rating = 200;
|
||||||
cd->irq = irq;
|
cd->irq = irq;
|
||||||
cd->cpumask = cpumask_of(cpu);
|
cd->cpumask = cpumask_of(cpu);
|
||||||
|
@ -128,7 +128,9 @@ int __init ds1287_clockevent_init(int irq)
|
|||||||
cd->irq = irq;
|
cd->irq = irq;
|
||||||
clockevent_set_clock(cd, 32768);
|
clockevent_set_clock(cd, 32768);
|
||||||
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
|
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
|
||||||
|
cd->max_delta_ticks = 0x7fffffff;
|
||||||
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
|
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
|
||||||
|
cd->min_delta_ticks = 0x300;
|
||||||
cd->cpumask = cpumask_of(0);
|
cd->cpumask = cpumask_of(0);
|
||||||
|
|
||||||
clockevents_register_device(&ds1287_clockevent);
|
clockevents_register_device(&ds1287_clockevent);
|
||||||
|
@ -152,7 +152,9 @@ static int __init gt641xx_timer0_clockevent_init(void)
|
|||||||
cd->rating = 200 + gt641xx_base_clock / 10000000;
|
cd->rating = 200 + gt641xx_base_clock / 10000000;
|
||||||
clockevent_set_clock(cd, gt641xx_base_clock);
|
clockevent_set_clock(cd, gt641xx_base_clock);
|
||||||
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
|
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
|
||||||
|
cd->max_delta_ticks = 0x7fffffff;
|
||||||
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
|
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
|
||||||
|
cd->min_delta_ticks = 0x300;
|
||||||
cd->cpumask = cpumask_of(0);
|
cd->cpumask = cpumask_of(0);
|
||||||
|
|
||||||
clockevents_register_device(>641xx_timer0_clockevent);
|
clockevents_register_device(>641xx_timer0_clockevent);
|
||||||
|
@ -123,7 +123,9 @@ void sb1250_clockevent_init(void)
|
|||||||
CLOCK_EVT_FEAT_ONESHOT;
|
CLOCK_EVT_FEAT_ONESHOT;
|
||||||
clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
|
clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
|
||||||
cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd);
|
cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd);
|
||||||
|
cd->max_delta_ticks = 0x7fffff;
|
||||||
cd->min_delta_ns = clockevent_delta2ns(2, cd);
|
cd->min_delta_ns = clockevent_delta2ns(2, cd);
|
||||||
|
cd->min_delta_ticks = 2;
|
||||||
cd->rating = 200;
|
cd->rating = 200;
|
||||||
cd->irq = irq;
|
cd->irq = irq;
|
||||||
cd->cpumask = cpumask_of(cpu);
|
cd->cpumask = cpumask_of(cpu);
|
||||||
|
@ -196,7 +196,9 @@ void __init txx9_clockevent_init(unsigned long baseaddr, int irq,
|
|||||||
clockevent_set_clock(cd, TIMER_CLK(imbusclk));
|
clockevent_set_clock(cd, TIMER_CLK(imbusclk));
|
||||||
cd->max_delta_ns =
|
cd->max_delta_ns =
|
||||||
clockevent_delta2ns(0xffffffff >> (32 - TXX9_TIMER_BITS), cd);
|
clockevent_delta2ns(0xffffffff >> (32 - TXX9_TIMER_BITS), cd);
|
||||||
|
cd->max_delta_ticks = 0xffffffff >> (32 - TXX9_TIMER_BITS);
|
||||||
cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
|
cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
|
||||||
|
cd->min_delta_ticks = 0xf;
|
||||||
cd->irq = irq;
|
cd->irq = irq;
|
||||||
cd->cpumask = cpumask_of(0),
|
cd->cpumask = cpumask_of(0),
|
||||||
clockevents_register_device(cd);
|
clockevents_register_device(cd);
|
||||||
|
@ -199,7 +199,9 @@ static void __init ls1x_time_init(void)
|
|||||||
|
|
||||||
clockevent_set_clock(cd, mips_hpt_frequency);
|
clockevent_set_clock(cd, mips_hpt_frequency);
|
||||||
cd->max_delta_ns = clockevent_delta2ns(0xffffff, cd);
|
cd->max_delta_ns = clockevent_delta2ns(0xffffff, cd);
|
||||||
|
cd->max_delta_ticks = 0xffffff;
|
||||||
cd->min_delta_ns = clockevent_delta2ns(0x000300, cd);
|
cd->min_delta_ns = clockevent_delta2ns(0x000300, cd);
|
||||||
|
cd->min_delta_ticks = 0x000300;
|
||||||
cd->cpumask = cpumask_of(smp_processor_id());
|
cd->cpumask = cpumask_of(smp_processor_id());
|
||||||
clockevents_register_device(cd);
|
clockevents_register_device(cd);
|
||||||
|
|
||||||
|
@ -123,7 +123,9 @@ void __init setup_mfgpt0_timer(void)
|
|||||||
cd->cpumask = cpumask_of(cpu);
|
cd->cpumask = cpumask_of(cpu);
|
||||||
clockevent_set_clock(cd, MFGPT_TICK_RATE);
|
clockevent_set_clock(cd, MFGPT_TICK_RATE);
|
||||||
cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
|
cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
|
||||||
|
cd->max_delta_ticks = 0xffff;
|
||||||
cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
|
cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
|
||||||
|
cd->min_delta_ticks = 0xf;
|
||||||
|
|
||||||
/* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */
|
/* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */
|
||||||
_wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
|
_wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
|
||||||
|
@ -241,7 +241,9 @@ void __init setup_hpet_timer(void)
|
|||||||
cd->cpumask = cpumask_of(cpu);
|
cd->cpumask = cpumask_of(cpu);
|
||||||
clockevent_set_clock(cd, HPET_FREQ);
|
clockevent_set_clock(cd, HPET_FREQ);
|
||||||
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
|
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
|
||||||
|
cd->max_delta_ticks = 0x7fffffff;
|
||||||
cd->min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, cd);
|
cd->min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, cd);
|
||||||
|
cd->min_delta_ticks = HPET_MIN_PROG_DELTA;
|
||||||
|
|
||||||
clockevents_register_device(cd);
|
clockevents_register_device(cd);
|
||||||
setup_irq(HPET_T0_IRQ, &hpet_irq);
|
setup_irq(HPET_T0_IRQ, &hpet_irq);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <linux/i8253.h>
|
#include <linux/i8253.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/kernel_stat.h>
|
#include <linux/kernel_stat.h>
|
||||||
|
#include <linux/libfdt.h>
|
||||||
#include <linux/math64.h>
|
#include <linux/math64.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
@ -207,6 +208,33 @@ static void __init init_rtc(void)
|
|||||||
CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL);
|
CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_CLKSRC_MIPS_GIC
|
||||||
|
static u32 gic_frequency_dt;
|
||||||
|
|
||||||
|
static struct property gic_frequency_prop = {
|
||||||
|
.name = "clock-frequency",
|
||||||
|
.length = sizeof(u32),
|
||||||
|
.value = &gic_frequency_dt,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void update_gic_frequency_dt(void)
|
||||||
|
{
|
||||||
|
struct device_node *node;
|
||||||
|
|
||||||
|
gic_frequency_dt = cpu_to_be32(gic_frequency);
|
||||||
|
|
||||||
|
node = of_find_compatible_node(NULL, NULL, "mti,gic-timer");
|
||||||
|
if (!node) {
|
||||||
|
pr_err("mti,gic-timer device node not found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of_update_property(node, &gic_frequency_prop) < 0)
|
||||||
|
pr_err("error updating gic frequency property\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void __init plat_time_init(void)
|
void __init plat_time_init(void)
|
||||||
{
|
{
|
||||||
unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK);
|
unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK);
|
||||||
@ -236,7 +264,8 @@ void __init plat_time_init(void)
|
|||||||
printk("GIC frequency %d.%02d MHz\n", freq/1000000,
|
printk("GIC frequency %d.%02d MHz\n", freq/1000000,
|
||||||
(freq%1000000)*100/1000000);
|
(freq%1000000)*100/1000000);
|
||||||
#ifdef CONFIG_CLKSRC_MIPS_GIC
|
#ifdef CONFIG_CLKSRC_MIPS_GIC
|
||||||
gic_clocksource_init(gic_frequency);
|
update_gic_frequency_dt();
|
||||||
|
clocksource_probe();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -129,7 +129,9 @@ static int __init ralink_systick_init(struct device_node *np)
|
|||||||
systick.dev.name = np->name;
|
systick.dev.name = np->name;
|
||||||
clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
|
clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
|
||||||
systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
|
systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
|
||||||
|
systick.dev.max_delta_ticks = 0x7fff;
|
||||||
systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
|
systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
|
||||||
|
systick.dev.min_delta_ticks = 0x3;
|
||||||
systick.dev.irq = irq_of_parse_and_map(np, 0);
|
systick.dev.irq = irq_of_parse_and_map(np, 0);
|
||||||
if (!systick.dev.irq) {
|
if (!systick.dev.irq) {
|
||||||
pr_err("%s: request_irq failed", np->name);
|
pr_err("%s: request_irq failed", np->name);
|
||||||
|
@ -113,7 +113,9 @@ void hub_rt_clock_event_init(void)
|
|||||||
cd->features = CLOCK_EVT_FEAT_ONESHOT;
|
cd->features = CLOCK_EVT_FEAT_ONESHOT;
|
||||||
clockevent_set_clock(cd, CYCLES_PER_SEC);
|
clockevent_set_clock(cd, CYCLES_PER_SEC);
|
||||||
cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd);
|
cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd);
|
||||||
|
cd->max_delta_ticks = 0xfffffffffffff;
|
||||||
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
|
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
|
||||||
|
cd->min_delta_ticks = 0x300;
|
||||||
cd->rating = 200;
|
cd->rating = 200;
|
||||||
cd->irq = irq;
|
cd->irq = irq;
|
||||||
cd->cpumask = cpumask_of(cpu);
|
cd->cpumask = cpumask_of(cpu);
|
||||||
|
@ -98,7 +98,9 @@ int __init init_clockevents(void)
|
|||||||
|
|
||||||
/* Calculate the min / max delta */
|
/* Calculate the min / max delta */
|
||||||
cd->max_delta_ns = clockevent_delta2ns(TMJCBR_MAX, cd);
|
cd->max_delta_ns = clockevent_delta2ns(TMJCBR_MAX, cd);
|
||||||
|
cd->max_delta_ticks = TMJCBR_MAX;
|
||||||
cd->min_delta_ns = clockevent_delta2ns(100, cd);
|
cd->min_delta_ns = clockevent_delta2ns(100, cd);
|
||||||
|
cd->min_delta_ticks = 100;
|
||||||
|
|
||||||
cd->rating = 200;
|
cd->rating = 200;
|
||||||
cd->cpumask = cpumask_of(smp_processor_id());
|
cd->cpumask = cpumask_of(smp_processor_id());
|
||||||
|
@ -995,8 +995,10 @@ static void __init init_decrementer_clockevent(void)
|
|||||||
|
|
||||||
decrementer_clockevent.max_delta_ns =
|
decrementer_clockevent.max_delta_ns =
|
||||||
clockevent_delta2ns(decrementer_max, &decrementer_clockevent);
|
clockevent_delta2ns(decrementer_max, &decrementer_clockevent);
|
||||||
|
decrementer_clockevent.max_delta_ticks = decrementer_max;
|
||||||
decrementer_clockevent.min_delta_ns =
|
decrementer_clockevent.min_delta_ns =
|
||||||
clockevent_delta2ns(2, &decrementer_clockevent);
|
clockevent_delta2ns(2, &decrementer_clockevent);
|
||||||
|
decrementer_clockevent.min_delta_ticks = 2;
|
||||||
|
|
||||||
register_decrementer_clockevent(cpu);
|
register_decrementer_clockevent(cpu);
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,9 @@ void init_cpu_timer(void)
|
|||||||
cd->mult = 16777;
|
cd->mult = 16777;
|
||||||
cd->shift = 12;
|
cd->shift = 12;
|
||||||
cd->min_delta_ns = 1;
|
cd->min_delta_ns = 1;
|
||||||
|
cd->min_delta_ticks = 1;
|
||||||
cd->max_delta_ns = LONG_MAX;
|
cd->max_delta_ns = LONG_MAX;
|
||||||
|
cd->max_delta_ticks = ULONG_MAX;
|
||||||
cd->rating = 400;
|
cd->rating = 400;
|
||||||
cd->cpumask = cpumask_of(cpu);
|
cd->cpumask = cpumask_of(cpu);
|
||||||
cd->set_next_event = s390_next_event;
|
cd->set_next_event = s390_next_event;
|
||||||
|
@ -81,8 +81,10 @@ void __init time_init(void)
|
|||||||
score_clockevent.shift);
|
score_clockevent.shift);
|
||||||
score_clockevent.max_delta_ns = clockevent_delta2ns((u32)~0,
|
score_clockevent.max_delta_ns = clockevent_delta2ns((u32)~0,
|
||||||
&score_clockevent);
|
&score_clockevent);
|
||||||
|
score_clockevent.max_delta_ticks = (u32)~0;
|
||||||
score_clockevent.min_delta_ns = clockevent_delta2ns(50,
|
score_clockevent.min_delta_ns = clockevent_delta2ns(50,
|
||||||
&score_clockevent) + 1;
|
&score_clockevent) + 1;
|
||||||
|
score_clockevent.min_delta_ticks = 50;
|
||||||
score_clockevent.cpumask = cpumask_of(0);
|
score_clockevent.cpumask = cpumask_of(0);
|
||||||
clockevents_register_device(&score_clockevent);
|
clockevents_register_device(&score_clockevent);
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,9 @@ void register_percpu_ce(int cpu)
|
|||||||
ce->mult = div_sc(sparc_config.clock_rate, NSEC_PER_SEC,
|
ce->mult = div_sc(sparc_config.clock_rate, NSEC_PER_SEC,
|
||||||
ce->shift);
|
ce->shift);
|
||||||
ce->max_delta_ns = clockevent_delta2ns(sparc_config.clock_rate, ce);
|
ce->max_delta_ns = clockevent_delta2ns(sparc_config.clock_rate, ce);
|
||||||
|
ce->max_delta_ticks = (unsigned long)sparc_config.clock_rate;
|
||||||
ce->min_delta_ns = clockevent_delta2ns(100, ce);
|
ce->min_delta_ns = clockevent_delta2ns(100, ce);
|
||||||
|
ce->min_delta_ticks = 100;
|
||||||
|
|
||||||
clockevents_register_device(ce);
|
clockevents_register_device(ce);
|
||||||
}
|
}
|
||||||
|
@ -796,8 +796,10 @@ void __init time_init(void)
|
|||||||
|
|
||||||
sparc64_clockevent.max_delta_ns =
|
sparc64_clockevent.max_delta_ns =
|
||||||
clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent);
|
clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent);
|
||||||
|
sparc64_clockevent.max_delta_ticks = 0x7fffffffffffffffUL;
|
||||||
sparc64_clockevent.min_delta_ns =
|
sparc64_clockevent.min_delta_ns =
|
||||||
clockevent_delta2ns(0xF, &sparc64_clockevent);
|
clockevent_delta2ns(0xF, &sparc64_clockevent);
|
||||||
|
sparc64_clockevent.min_delta_ticks = 0xF;
|
||||||
|
|
||||||
printk("clockevent: mult[%x] shift[%d]\n",
|
printk("clockevent: mult[%x] shift[%d]\n",
|
||||||
sparc64_clockevent.mult, sparc64_clockevent.shift);
|
sparc64_clockevent.mult, sparc64_clockevent.shift);
|
||||||
|
@ -155,6 +155,8 @@ static DEFINE_PER_CPU(struct clock_event_device, tile_timer) = {
|
|||||||
.name = "tile timer",
|
.name = "tile timer",
|
||||||
.features = CLOCK_EVT_FEAT_ONESHOT,
|
.features = CLOCK_EVT_FEAT_ONESHOT,
|
||||||
.min_delta_ns = 1000,
|
.min_delta_ns = 1000,
|
||||||
|
.min_delta_ticks = 1,
|
||||||
|
.max_delta_ticks = MAX_TICK,
|
||||||
.rating = 100,
|
.rating = 100,
|
||||||
.irq = -1,
|
.irq = -1,
|
||||||
.set_next_event = tile_timer_set_next_event,
|
.set_next_event = tile_timer_set_next_event,
|
||||||
|
@ -65,7 +65,9 @@ static struct clock_event_device timer_clockevent = {
|
|||||||
.set_next_event = itimer_next_event,
|
.set_next_event = itimer_next_event,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
.max_delta_ns = 0xffffffff,
|
.max_delta_ns = 0xffffffff,
|
||||||
.min_delta_ns = TIMER_MIN_DELTA, //microsecond resolution should be enough for anyone, same as 640K RAM
|
.max_delta_ticks = 0xffffffff,
|
||||||
|
.min_delta_ns = TIMER_MIN_DELTA,
|
||||||
|
.min_delta_ticks = TIMER_MIN_DELTA, // microsecond resolution should be enough for anyone, same as 640K RAM
|
||||||
.irq = 0,
|
.irq = 0,
|
||||||
.mult = 1,
|
.mult = 1,
|
||||||
};
|
};
|
||||||
|
@ -91,8 +91,10 @@ void __init time_init(void)
|
|||||||
|
|
||||||
ckevt_puv3_osmr0.max_delta_ns =
|
ckevt_puv3_osmr0.max_delta_ns =
|
||||||
clockevent_delta2ns(0x7fffffff, &ckevt_puv3_osmr0);
|
clockevent_delta2ns(0x7fffffff, &ckevt_puv3_osmr0);
|
||||||
|
ckevt_puv3_osmr0.max_delta_ticks = 0x7fffffff;
|
||||||
ckevt_puv3_osmr0.min_delta_ns =
|
ckevt_puv3_osmr0.min_delta_ns =
|
||||||
clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_puv3_osmr0) + 1;
|
clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_puv3_osmr0) + 1;
|
||||||
|
ckevt_puv3_osmr0.min_delta_ticks = MIN_OSCR_DELTA * 2;
|
||||||
ckevt_puv3_osmr0.cpumask = cpumask_of(0);
|
ckevt_puv3_osmr0.cpumask = cpumask_of(0);
|
||||||
|
|
||||||
setup_irq(IRQ_TIMER0, &puv3_timer_irq);
|
setup_irq(IRQ_TIMER0, &puv3_timer_irq);
|
||||||
|
@ -731,8 +731,10 @@ static int __init calibrate_APIC_clock(void)
|
|||||||
TICK_NSEC, lapic_clockevent.shift);
|
TICK_NSEC, lapic_clockevent.shift);
|
||||||
lapic_clockevent.max_delta_ns =
|
lapic_clockevent.max_delta_ns =
|
||||||
clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
|
clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
|
||||||
|
lapic_clockevent.max_delta_ticks = 0x7FFFFF;
|
||||||
lapic_clockevent.min_delta_ns =
|
lapic_clockevent.min_delta_ns =
|
||||||
clockevent_delta2ns(0xF, &lapic_clockevent);
|
clockevent_delta2ns(0xF, &lapic_clockevent);
|
||||||
|
lapic_clockevent.min_delta_ticks = 0xF;
|
||||||
lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
|
lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -778,8 +780,10 @@ static int __init calibrate_APIC_clock(void)
|
|||||||
lapic_clockevent.shift);
|
lapic_clockevent.shift);
|
||||||
lapic_clockevent.max_delta_ns =
|
lapic_clockevent.max_delta_ns =
|
||||||
clockevent_delta2ns(0x7FFFFFFF, &lapic_clockevent);
|
clockevent_delta2ns(0x7FFFFFFF, &lapic_clockevent);
|
||||||
|
lapic_clockevent.max_delta_ticks = 0x7FFFFFFF;
|
||||||
lapic_clockevent.min_delta_ns =
|
lapic_clockevent.min_delta_ns =
|
||||||
clockevent_delta2ns(0xF, &lapic_clockevent);
|
clockevent_delta2ns(0xF, &lapic_clockevent);
|
||||||
|
lapic_clockevent.min_delta_ticks = 0xF;
|
||||||
|
|
||||||
lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
|
lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
|
||||||
|
|
||||||
|
@ -994,7 +994,9 @@ static struct clock_event_device lguest_clockevent = {
|
|||||||
.mult = 1,
|
.mult = 1,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
.min_delta_ns = LG_CLOCK_MIN_DELTA,
|
.min_delta_ns = LG_CLOCK_MIN_DELTA,
|
||||||
|
.min_delta_ticks = LG_CLOCK_MIN_DELTA,
|
||||||
.max_delta_ns = LG_CLOCK_MAX_DELTA,
|
.max_delta_ns = LG_CLOCK_MAX_DELTA,
|
||||||
|
.max_delta_ticks = LG_CLOCK_MAX_DELTA,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -390,9 +390,11 @@ static __init int uv_rtc_setup_clock(void)
|
|||||||
|
|
||||||
clock_event_device_uv.min_delta_ns = NSEC_PER_SEC /
|
clock_event_device_uv.min_delta_ns = NSEC_PER_SEC /
|
||||||
sn_rtc_cycles_per_second;
|
sn_rtc_cycles_per_second;
|
||||||
|
clock_event_device_uv.min_delta_ticks = 1;
|
||||||
|
|
||||||
clock_event_device_uv.max_delta_ns = clocksource_uv.mask *
|
clock_event_device_uv.max_delta_ns = clocksource_uv.mask *
|
||||||
(NSEC_PER_SEC / sn_rtc_cycles_per_second);
|
(NSEC_PER_SEC / sn_rtc_cycles_per_second);
|
||||||
|
clock_event_device_uv.max_delta_ticks = clocksource_uv.mask;
|
||||||
|
|
||||||
rc = schedule_on_each_cpu(uv_rtc_register_clockevents);
|
rc = schedule_on_each_cpu(uv_rtc_register_clockevents);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -209,7 +209,9 @@ static const struct clock_event_device xen_timerop_clockevent = {
|
|||||||
.features = CLOCK_EVT_FEAT_ONESHOT,
|
.features = CLOCK_EVT_FEAT_ONESHOT,
|
||||||
|
|
||||||
.max_delta_ns = 0xffffffff,
|
.max_delta_ns = 0xffffffff,
|
||||||
|
.max_delta_ticks = 0xffffffff,
|
||||||
.min_delta_ns = TIMER_SLOP,
|
.min_delta_ns = TIMER_SLOP,
|
||||||
|
.min_delta_ticks = TIMER_SLOP,
|
||||||
|
|
||||||
.mult = 1,
|
.mult = 1,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
@ -268,7 +270,9 @@ static const struct clock_event_device xen_vcpuop_clockevent = {
|
|||||||
.features = CLOCK_EVT_FEAT_ONESHOT,
|
.features = CLOCK_EVT_FEAT_ONESHOT,
|
||||||
|
|
||||||
.max_delta_ns = 0xffffffff,
|
.max_delta_ns = 0xffffffff,
|
||||||
|
.max_delta_ticks = 0xffffffff,
|
||||||
.min_delta_ns = TIMER_SLOP,
|
.min_delta_ns = TIMER_SLOP,
|
||||||
|
.min_delta_ticks = TIMER_SLOP,
|
||||||
|
|
||||||
.mult = 1,
|
.mult = 1,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -4,3 +4,6 @@
|
|||||||
|
|
||||||
config ACPI_IORT
|
config ACPI_IORT
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config ACPI_GTDT
|
||||||
|
bool
|
||||||
|
@ -1 +1,2 @@
|
|||||||
obj-$(CONFIG_ACPI_IORT) += iort.o
|
obj-$(CONFIG_ACPI_IORT) += iort.o
|
||||||
|
obj-$(CONFIG_ACPI_GTDT) += gtdt.o
|
||||||
|
417
drivers/acpi/arm64/gtdt.c
Normal file
417
drivers/acpi/arm64/gtdt.c
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
/*
|
||||||
|
* ARM Specific GTDT table Support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016, Linaro Ltd.
|
||||||
|
* Author: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||||
|
* Fu Wei <fu.wei@linaro.org>
|
||||||
|
* Hanjun Guo <hanjun.guo@linaro.org>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#include <clocksource/arm_arch_timer.h>
|
||||||
|
|
||||||
|
#undef pr_fmt
|
||||||
|
#define pr_fmt(fmt) "ACPI GTDT: " fmt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct acpi_gtdt_descriptor - Store the key info of GTDT for all functions
|
||||||
|
* @gtdt: The pointer to the struct acpi_table_gtdt of GTDT table.
|
||||||
|
* @gtdt_end: The pointer to the end of GTDT table.
|
||||||
|
* @platform_timer: The pointer to the start of Platform Timer Structure
|
||||||
|
*
|
||||||
|
* The struct store the key info of GTDT table, it should be initialized by
|
||||||
|
* acpi_gtdt_init.
|
||||||
|
*/
|
||||||
|
struct acpi_gtdt_descriptor {
|
||||||
|
struct acpi_table_gtdt *gtdt;
|
||||||
|
void *gtdt_end;
|
||||||
|
void *platform_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
|
||||||
|
|
||||||
|
static inline void *next_platform_timer(void *platform_timer)
|
||||||
|
{
|
||||||
|
struct acpi_gtdt_header *gh = platform_timer;
|
||||||
|
|
||||||
|
platform_timer += gh->length;
|
||||||
|
if (platform_timer < acpi_gtdt_desc.gtdt_end)
|
||||||
|
return platform_timer;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define for_each_platform_timer(_g) \
|
||||||
|
for (_g = acpi_gtdt_desc.platform_timer; _g; \
|
||||||
|
_g = next_platform_timer(_g))
|
||||||
|
|
||||||
|
static inline bool is_timer_block(void *platform_timer)
|
||||||
|
{
|
||||||
|
struct acpi_gtdt_header *gh = platform_timer;
|
||||||
|
|
||||||
|
return gh->type == ACPI_GTDT_TYPE_TIMER_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_non_secure_watchdog(void *platform_timer)
|
||||||
|
{
|
||||||
|
struct acpi_gtdt_header *gh = platform_timer;
|
||||||
|
struct acpi_gtdt_watchdog *wd = platform_timer;
|
||||||
|
|
||||||
|
if (gh->type != ACPI_GTDT_TYPE_WATCHDOG)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !(wd->timer_flags & ACPI_GTDT_WATCHDOG_SECURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init map_gt_gsi(u32 interrupt, u32 flags)
|
||||||
|
{
|
||||||
|
int trigger, polarity;
|
||||||
|
|
||||||
|
trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
|
||||||
|
: ACPI_LEVEL_SENSITIVE;
|
||||||
|
|
||||||
|
polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
|
||||||
|
: ACPI_ACTIVE_HIGH;
|
||||||
|
|
||||||
|
return acpi_register_gsi(NULL, interrupt, trigger, polarity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acpi_gtdt_map_ppi() - Map the PPIs of per-cpu arch_timer.
|
||||||
|
* @type: the type of PPI.
|
||||||
|
*
|
||||||
|
* Note: Secure state is not managed by the kernel on ARM64 systems.
|
||||||
|
* So we only handle the non-secure timer PPIs,
|
||||||
|
* ARCH_TIMER_PHYS_SECURE_PPI is treated as invalid type.
|
||||||
|
*
|
||||||
|
* Return: the mapped PPI value, 0 if error.
|
||||||
|
*/
|
||||||
|
int __init acpi_gtdt_map_ppi(int type)
|
||||||
|
{
|
||||||
|
struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ARCH_TIMER_PHYS_NONSECURE_PPI:
|
||||||
|
return map_gt_gsi(gtdt->non_secure_el1_interrupt,
|
||||||
|
gtdt->non_secure_el1_flags);
|
||||||
|
case ARCH_TIMER_VIRT_PPI:
|
||||||
|
return map_gt_gsi(gtdt->virtual_timer_interrupt,
|
||||||
|
gtdt->virtual_timer_flags);
|
||||||
|
|
||||||
|
case ARCH_TIMER_HYP_PPI:
|
||||||
|
return map_gt_gsi(gtdt->non_secure_el2_interrupt,
|
||||||
|
gtdt->non_secure_el2_flags);
|
||||||
|
default:
|
||||||
|
pr_err("Failed to map timer interrupt: invalid type.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acpi_gtdt_c3stop() - Got c3stop info from GTDT according to the type of PPI.
|
||||||
|
* @type: the type of PPI.
|
||||||
|
*
|
||||||
|
* Return: true if the timer HW state is lost when a CPU enters an idle state,
|
||||||
|
* false otherwise
|
||||||
|
*/
|
||||||
|
bool __init acpi_gtdt_c3stop(int type)
|
||||||
|
{
|
||||||
|
struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ARCH_TIMER_PHYS_NONSECURE_PPI:
|
||||||
|
return !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
|
||||||
|
|
||||||
|
case ARCH_TIMER_VIRT_PPI:
|
||||||
|
return !(gtdt->virtual_timer_flags & ACPI_GTDT_ALWAYS_ON);
|
||||||
|
|
||||||
|
case ARCH_TIMER_HYP_PPI:
|
||||||
|
return !(gtdt->non_secure_el2_flags & ACPI_GTDT_ALWAYS_ON);
|
||||||
|
|
||||||
|
default:
|
||||||
|
pr_err("Failed to get c3stop info: invalid type.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acpi_gtdt_init() - Get the info of GTDT table to prepare for further init.
|
||||||
|
* @table: The pointer to GTDT table.
|
||||||
|
* @platform_timer_count: It points to a integer variable which is used
|
||||||
|
* for storing the number of platform timers.
|
||||||
|
* This pointer could be NULL, if the caller
|
||||||
|
* doesn't need this info.
|
||||||
|
*
|
||||||
|
* Return: 0 if success, -EINVAL if error.
|
||||||
|
*/
|
||||||
|
int __init acpi_gtdt_init(struct acpi_table_header *table,
|
||||||
|
int *platform_timer_count)
|
||||||
|
{
|
||||||
|
void *platform_timer;
|
||||||
|
struct acpi_table_gtdt *gtdt;
|
||||||
|
|
||||||
|
gtdt = container_of(table, struct acpi_table_gtdt, header);
|
||||||
|
acpi_gtdt_desc.gtdt = gtdt;
|
||||||
|
acpi_gtdt_desc.gtdt_end = (void *)table + table->length;
|
||||||
|
acpi_gtdt_desc.platform_timer = NULL;
|
||||||
|
if (platform_timer_count)
|
||||||
|
*platform_timer_count = 0;
|
||||||
|
|
||||||
|
if (table->revision < 2) {
|
||||||
|
pr_warn("Revision:%d doesn't support Platform Timers.\n",
|
||||||
|
table->revision);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gtdt->platform_timer_count) {
|
||||||
|
pr_debug("No Platform Timer.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_timer = (void *)gtdt + gtdt->platform_timer_offset;
|
||||||
|
if (platform_timer < (void *)table + sizeof(struct acpi_table_gtdt)) {
|
||||||
|
pr_err(FW_BUG "invalid timer data.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
acpi_gtdt_desc.platform_timer = platform_timer;
|
||||||
|
if (platform_timer_count)
|
||||||
|
*platform_timer_count = gtdt->platform_timer_count;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init gtdt_parse_timer_block(struct acpi_gtdt_timer_block *block,
|
||||||
|
struct arch_timer_mem *timer_mem)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct arch_timer_mem_frame *frame;
|
||||||
|
struct acpi_gtdt_timer_entry *gtdt_frame;
|
||||||
|
|
||||||
|
if (!block->timer_count) {
|
||||||
|
pr_err(FW_BUG "GT block present, but frame count is zero.");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block->timer_count > ARCH_TIMER_MEM_MAX_FRAMES) {
|
||||||
|
pr_err(FW_BUG "GT block lists %d frames, ACPI spec only allows 8\n",
|
||||||
|
block->timer_count);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_mem->cntctlbase = (phys_addr_t)block->block_address;
|
||||||
|
/*
|
||||||
|
* The CNTCTLBase frame is 4KB (register offsets 0x000 - 0xFFC).
|
||||||
|
* See ARM DDI 0487A.k_iss10775, page I1-5129, Table I1-3
|
||||||
|
* "CNTCTLBase memory map".
|
||||||
|
*/
|
||||||
|
timer_mem->size = SZ_4K;
|
||||||
|
|
||||||
|
gtdt_frame = (void *)block + block->timer_offset;
|
||||||
|
if (gtdt_frame + block->timer_count != (void *)block + block->header.length)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the GT timer Frame data for every GT Block Timer
|
||||||
|
*/
|
||||||
|
for (i = 0; i < block->timer_count; i++, gtdt_frame++) {
|
||||||
|
if (gtdt_frame->common_flags & ACPI_GTDT_GT_IS_SECURE_TIMER)
|
||||||
|
continue;
|
||||||
|
if (gtdt_frame->frame_number >= ARCH_TIMER_MEM_MAX_FRAMES ||
|
||||||
|
!gtdt_frame->base_address || !gtdt_frame->timer_interrupt)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
frame = &timer_mem->frame[gtdt_frame->frame_number];
|
||||||
|
|
||||||
|
/* duplicate frame */
|
||||||
|
if (frame->valid)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
frame->phys_irq = map_gt_gsi(gtdt_frame->timer_interrupt,
|
||||||
|
gtdt_frame->timer_flags);
|
||||||
|
if (frame->phys_irq <= 0) {
|
||||||
|
pr_warn("failed to map physical timer irq in frame %d.\n",
|
||||||
|
gtdt_frame->frame_number);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gtdt_frame->virtual_timer_interrupt) {
|
||||||
|
frame->virt_irq =
|
||||||
|
map_gt_gsi(gtdt_frame->virtual_timer_interrupt,
|
||||||
|
gtdt_frame->virtual_timer_flags);
|
||||||
|
if (frame->virt_irq <= 0) {
|
||||||
|
pr_warn("failed to map virtual timer irq in frame %d.\n",
|
||||||
|
gtdt_frame->frame_number);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pr_debug("virtual timer in frame %d not implemented.\n",
|
||||||
|
gtdt_frame->frame_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->cntbase = gtdt_frame->base_address;
|
||||||
|
/*
|
||||||
|
* The CNTBaseN frame is 4KB (register offsets 0x000 - 0xFFC).
|
||||||
|
* See ARM DDI 0487A.k_iss10775, page I1-5130, Table I1-4
|
||||||
|
* "CNTBaseN memory map".
|
||||||
|
*/
|
||||||
|
frame->size = SZ_4K;
|
||||||
|
frame->valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
do {
|
||||||
|
if (gtdt_frame->common_flags & ACPI_GTDT_GT_IS_SECURE_TIMER ||
|
||||||
|
gtdt_frame->frame_number >= ARCH_TIMER_MEM_MAX_FRAMES)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
frame = &timer_mem->frame[gtdt_frame->frame_number];
|
||||||
|
|
||||||
|
if (frame->phys_irq > 0)
|
||||||
|
acpi_unregister_gsi(gtdt_frame->timer_interrupt);
|
||||||
|
frame->phys_irq = 0;
|
||||||
|
|
||||||
|
if (frame->virt_irq > 0)
|
||||||
|
acpi_unregister_gsi(gtdt_frame->virtual_timer_interrupt);
|
||||||
|
frame->virt_irq = 0;
|
||||||
|
} while (i-- >= 0 && gtdt_frame--);
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acpi_arch_timer_mem_init() - Get the info of all GT blocks in GTDT table.
|
||||||
|
* @timer_mem: The pointer to the array of struct arch_timer_mem for returning
|
||||||
|
* the result of parsing. The element number of this array should
|
||||||
|
* be platform_timer_count(the total number of platform timers).
|
||||||
|
* @timer_count: It points to a integer variable which is used for storing the
|
||||||
|
* number of GT blocks we have parsed.
|
||||||
|
*
|
||||||
|
* Return: 0 if success, -EINVAL/-ENODEV if error.
|
||||||
|
*/
|
||||||
|
int __init acpi_arch_timer_mem_init(struct arch_timer_mem *timer_mem,
|
||||||
|
int *timer_count)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
void *platform_timer;
|
||||||
|
|
||||||
|
*timer_count = 0;
|
||||||
|
for_each_platform_timer(platform_timer) {
|
||||||
|
if (is_timer_block(platform_timer)) {
|
||||||
|
ret = gtdt_parse_timer_block(platform_timer, timer_mem);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
timer_mem++;
|
||||||
|
(*timer_count)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*timer_count)
|
||||||
|
pr_info("found %d memory-mapped timer block(s).\n",
|
||||||
|
*timer_count);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a SBSA generic Watchdog platform device info from GTDT
|
||||||
|
*/
|
||||||
|
static int __init gtdt_import_sbsa_gwdt(struct acpi_gtdt_watchdog *wd,
|
||||||
|
int index)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev;
|
||||||
|
int irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* According to SBSA specification the size of refresh and control
|
||||||
|
* frames of SBSA Generic Watchdog is SZ_4K(Offset 0x000 – 0xFFF).
|
||||||
|
*/
|
||||||
|
struct resource res[] = {
|
||||||
|
DEFINE_RES_MEM(wd->control_frame_address, SZ_4K),
|
||||||
|
DEFINE_RES_MEM(wd->refresh_frame_address, SZ_4K),
|
||||||
|
DEFINE_RES_IRQ(irq),
|
||||||
|
};
|
||||||
|
int nr_res = ARRAY_SIZE(res);
|
||||||
|
|
||||||
|
pr_debug("found a Watchdog (0x%llx/0x%llx gsi:%u flags:0x%x).\n",
|
||||||
|
wd->refresh_frame_address, wd->control_frame_address,
|
||||||
|
wd->timer_interrupt, wd->timer_flags);
|
||||||
|
|
||||||
|
if (!(wd->refresh_frame_address && wd->control_frame_address)) {
|
||||||
|
pr_err(FW_BUG "failed to get the Watchdog base address.\n");
|
||||||
|
acpi_unregister_gsi(wd->timer_interrupt);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irq <= 0) {
|
||||||
|
pr_warn("failed to map the Watchdog interrupt.\n");
|
||||||
|
nr_res--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a platform device named "sbsa-gwdt" to match the platform driver.
|
||||||
|
* "sbsa-gwdt": SBSA(Server Base System Architecture) Generic Watchdog
|
||||||
|
* The platform driver can get device info below by matching this name.
|
||||||
|
*/
|
||||||
|
pdev = platform_device_register_simple("sbsa-gwdt", index, res, nr_res);
|
||||||
|
if (IS_ERR(pdev)) {
|
||||||
|
acpi_unregister_gsi(wd->timer_interrupt);
|
||||||
|
return PTR_ERR(pdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init gtdt_sbsa_gwdt_init(void)
|
||||||
|
{
|
||||||
|
void *platform_timer;
|
||||||
|
struct acpi_table_header *table;
|
||||||
|
int ret, timer_count, gwdt_count = 0;
|
||||||
|
|
||||||
|
if (acpi_disabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0, &table)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: Even though the global variable acpi_gtdt_desc has been
|
||||||
|
* initialized by acpi_gtdt_init() while initializing the arch timers,
|
||||||
|
* when we call this function to get SBSA watchdogs info from GTDT, the
|
||||||
|
* pointers stashed in it are stale (since they are early temporary
|
||||||
|
* mappings carried out before acpi_permanent_mmap is set) and we need
|
||||||
|
* to re-initialize them with permanent mapped pointer values to let the
|
||||||
|
* GTDT parsing possible.
|
||||||
|
*/
|
||||||
|
ret = acpi_gtdt_init(table, &timer_count);
|
||||||
|
if (ret || !timer_count)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for_each_platform_timer(platform_timer) {
|
||||||
|
if (is_non_secure_watchdog(platform_timer)) {
|
||||||
|
ret = gtdt_import_sbsa_gwdt(platform_timer, gwdt_count);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
gwdt_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gwdt_count)
|
||||||
|
pr_info("found %d SBSA generic Watchdog(s).\n", gwdt_count);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_initcall(gtdt_sbsa_gwdt_init);
|
@ -478,18 +478,18 @@ static int sgi_clock_period;
|
|||||||
static struct timespec sgi_clock_offset;
|
static struct timespec sgi_clock_offset;
|
||||||
static int sgi_clock_period;
|
static int sgi_clock_period;
|
||||||
|
|
||||||
static int sgi_clock_get(clockid_t clockid, struct timespec *tp)
|
static int sgi_clock_get(clockid_t clockid, struct timespec64 *tp)
|
||||||
{
|
{
|
||||||
u64 nsec;
|
u64 nsec;
|
||||||
|
|
||||||
nsec = rtc_time() * sgi_clock_period
|
nsec = rtc_time() * sgi_clock_period
|
||||||
+ sgi_clock_offset.tv_nsec;
|
+ sgi_clock_offset.tv_nsec;
|
||||||
*tp = ns_to_timespec(nsec);
|
*tp = ns_to_timespec64(nsec);
|
||||||
tp->tv_sec += sgi_clock_offset.tv_sec;
|
tp->tv_sec += sgi_clock_offset.tv_sec;
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sgi_clock_set(const clockid_t clockid, const struct timespec *tp)
|
static int sgi_clock_set(const clockid_t clockid, const struct timespec64 *tp)
|
||||||
{
|
{
|
||||||
|
|
||||||
u64 nsec;
|
u64 nsec;
|
||||||
@ -657,7 +657,7 @@ static int sgi_timer_del(struct k_itimer *timr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Assumption: it_lock is already held with irq's disabled */
|
/* Assumption: it_lock is already held with irq's disabled */
|
||||||
static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
|
static void sgi_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (timr->it.mmtimer.clock == TIMER_OFF) {
|
if (timr->it.mmtimer.clock == TIMER_OFF) {
|
||||||
@ -668,14 +668,14 @@ static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_setting->it_interval = ns_to_timespec(timr->it.mmtimer.incr * sgi_clock_period);
|
cur_setting->it_interval = ns_to_timespec64(timr->it.mmtimer.incr * sgi_clock_period);
|
||||||
cur_setting->it_value = ns_to_timespec((timr->it.mmtimer.expires - rtc_time()) * sgi_clock_period);
|
cur_setting->it_value = ns_to_timespec64((timr->it.mmtimer.expires - rtc_time()) * sgi_clock_period);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int sgi_timer_set(struct k_itimer *timr, int flags,
|
static int sgi_timer_set(struct k_itimer *timr, int flags,
|
||||||
struct itimerspec * new_setting,
|
struct itimerspec64 *new_setting,
|
||||||
struct itimerspec * old_setting)
|
struct itimerspec64 *old_setting)
|
||||||
{
|
{
|
||||||
unsigned long when, period, irqflags;
|
unsigned long when, period, irqflags;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
@ -687,8 +687,8 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
|
|||||||
sgi_timer_get(timr, old_setting);
|
sgi_timer_get(timr, old_setting);
|
||||||
|
|
||||||
sgi_timer_del(timr);
|
sgi_timer_del(timr);
|
||||||
when = timespec_to_ns(&new_setting->it_value);
|
when = timespec64_to_ns(&new_setting->it_value);
|
||||||
period = timespec_to_ns(&new_setting->it_interval);
|
period = timespec64_to_ns(&new_setting->it_interval);
|
||||||
|
|
||||||
if (when == 0)
|
if (when == 0)
|
||||||
/* Clear timer */
|
/* Clear timer */
|
||||||
@ -699,11 +699,11 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (flags & TIMER_ABSTIME) {
|
if (flags & TIMER_ABSTIME) {
|
||||||
struct timespec n;
|
struct timespec64 n;
|
||||||
unsigned long now;
|
unsigned long now;
|
||||||
|
|
||||||
getnstimeofday(&n);
|
getnstimeofday64(&n);
|
||||||
now = timespec_to_ns(&n);
|
now = timespec64_to_ns(&n);
|
||||||
if (when > now)
|
if (when > now)
|
||||||
when -= now;
|
when -= now;
|
||||||
else
|
else
|
||||||
@ -765,7 +765,7 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sgi_clock_getres(const clockid_t which_clock, struct timespec *tp)
|
static int sgi_clock_getres(const clockid_t which_clock, struct timespec64 *tp)
|
||||||
{
|
{
|
||||||
tp->tv_sec = 0;
|
tp->tv_sec = 0;
|
||||||
tp->tv_nsec = sgi_clock_period;
|
tp->tv_nsec = sgi_clock_period;
|
||||||
|
@ -67,20 +67,22 @@ config DW_APB_TIMER_OF
|
|||||||
select DW_APB_TIMER
|
select DW_APB_TIMER
|
||||||
select CLKSRC_OF
|
select CLKSRC_OF
|
||||||
|
|
||||||
config GEMINI_TIMER
|
config FTTMR010_TIMER
|
||||||
bool "Cortina Gemini timer driver" if COMPILE_TEST
|
bool "Faraday Technology timer driver" if COMPILE_TEST
|
||||||
depends on GENERIC_CLOCKEVENTS
|
depends on GENERIC_CLOCKEVENTS
|
||||||
depends on HAS_IOMEM
|
depends on HAS_IOMEM
|
||||||
select CLKSRC_MMIO
|
select CLKSRC_MMIO
|
||||||
select CLKSRC_OF
|
select CLKSRC_OF
|
||||||
select MFD_SYSCON
|
select MFD_SYSCON
|
||||||
help
|
help
|
||||||
Enables support for the Gemini timer
|
Enables support for the Faraday Technology timer block
|
||||||
|
FTTMR010.
|
||||||
|
|
||||||
config ROCKCHIP_TIMER
|
config ROCKCHIP_TIMER
|
||||||
bool "Rockchip timer driver" if COMPILE_TEST
|
bool "Rockchip timer driver" if COMPILE_TEST
|
||||||
depends on ARM || ARM64
|
depends on ARM || ARM64
|
||||||
select CLKSRC_OF
|
select CLKSRC_OF
|
||||||
|
select CLKSRC_MMIO
|
||||||
help
|
help
|
||||||
Enables the support for the rockchip timer driver.
|
Enables the support for the rockchip timer driver.
|
||||||
|
|
||||||
@ -366,6 +368,17 @@ config HISILICON_ERRATUM_161010101
|
|||||||
161010101. The workaround will be active if the hisilicon,erratum-161010101
|
161010101. The workaround will be active if the hisilicon,erratum-161010101
|
||||||
property is found in the timer node.
|
property is found in the timer node.
|
||||||
|
|
||||||
|
config ARM64_ERRATUM_858921
|
||||||
|
bool "Workaround for Cortex-A73 erratum 858921"
|
||||||
|
default y
|
||||||
|
select ARM_ARCH_TIMER_OOL_WORKAROUND
|
||||||
|
depends on ARM_ARCH_TIMER && ARM64
|
||||||
|
help
|
||||||
|
This option enables a workaround applicable to Cortex-A73
|
||||||
|
(all versions), whose counter may return incorrect values.
|
||||||
|
The workaround will be dynamically enabled when an affected
|
||||||
|
core is detected.
|
||||||
|
|
||||||
config ARM_GLOBAL_TIMER
|
config ARM_GLOBAL_TIMER
|
||||||
bool "Support for the ARM global timer" if COMPILE_TEST
|
bool "Support for the ARM global timer" if COMPILE_TEST
|
||||||
select CLKSRC_OF if OF
|
select CLKSRC_OF if OF
|
||||||
|
@ -17,7 +17,7 @@ obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
|
|||||||
obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o
|
obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o
|
||||||
obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
|
obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
|
||||||
obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
|
obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
|
||||||
obj-$(CONFIG_GEMINI_TIMER) += timer-gemini.o
|
obj-$(CONFIG_FTTMR010_TIMER) += timer-fttmr010.o
|
||||||
obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
|
obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
|
||||||
obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
|
obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
|
||||||
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
|
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
|
||||||
|
@ -37,7 +37,7 @@ static int noinline arc_get_timer_clk(struct device_node *node)
|
|||||||
|
|
||||||
clk = of_clk_get(node, 0);
|
clk = of_clk_get(node, 0);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
pr_err("timer missing clk");
|
pr_err("timer missing clk\n");
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ static int __init arc_cs_setup_gfrc(struct device_node *node)
|
|||||||
|
|
||||||
READ_BCR(ARC_REG_MCIP_BCR, mp);
|
READ_BCR(ARC_REG_MCIP_BCR, mp);
|
||||||
if (!mp.gfrc) {
|
if (!mp.gfrc) {
|
||||||
pr_warn("Global-64-bit-Ctr clocksource not detected");
|
pr_warn("Global-64-bit-Ctr clocksource not detected\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,13 +140,13 @@ static int __init arc_cs_setup_rtc(struct device_node *node)
|
|||||||
|
|
||||||
READ_BCR(ARC_REG_TIMERS_BCR, timer);
|
READ_BCR(ARC_REG_TIMERS_BCR, timer);
|
||||||
if (!timer.rtc) {
|
if (!timer.rtc) {
|
||||||
pr_warn("Local-64-bit-Ctr clocksource not detected");
|
pr_warn("Local-64-bit-Ctr clocksource not detected\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Local to CPU hence not usable in SMP */
|
/* Local to CPU hence not usable in SMP */
|
||||||
if (IS_ENABLED(CONFIG_SMP)) {
|
if (IS_ENABLED(CONFIG_SMP)) {
|
||||||
pr_warn("Local-64-bit-Ctr not usable in SMP");
|
pr_warn("Local-64-bit-Ctr not usable in SMP\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,13 +290,13 @@ static int __init arc_clockevent_setup(struct device_node *node)
|
|||||||
|
|
||||||
arc_timer_irq = irq_of_parse_and_map(node, 0);
|
arc_timer_irq = irq_of_parse_and_map(node, 0);
|
||||||
if (arc_timer_irq <= 0) {
|
if (arc_timer_irq <= 0) {
|
||||||
pr_err("clockevent: missing irq");
|
pr_err("clockevent: missing irq\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = arc_get_timer_clk(node);
|
ret = arc_get_timer_clk(node);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("clockevent: missing clk");
|
pr_err("clockevent: missing clk\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +313,7 @@ static int __init arc_clockevent_setup(struct device_node *node)
|
|||||||
arc_timer_starting_cpu,
|
arc_timer_starting_cpu,
|
||||||
arc_timer_dying_cpu);
|
arc_timer_dying_cpu);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to setup hotplug state");
|
pr_err("Failed to setup hotplug state\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -193,7 +193,7 @@ static int __init asm9260_timer_init(struct device_node *np)
|
|||||||
|
|
||||||
priv.base = of_io_request_and_map(np, 0, np->name);
|
priv.base = of_io_request_and_map(np, 0, np->name);
|
||||||
if (IS_ERR(priv.base)) {
|
if (IS_ERR(priv.base)) {
|
||||||
pr_err("%s: unable to map resource", np->name);
|
pr_err("%s: unable to map resource\n", np->name);
|
||||||
return PTR_ERR(priv.base);
|
return PTR_ERR(priv.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,13 +89,13 @@ static int __init bcm2835_timer_init(struct device_node *node)
|
|||||||
|
|
||||||
base = of_iomap(node, 0);
|
base = of_iomap(node, 0);
|
||||||
if (!base) {
|
if (!base) {
|
||||||
pr_err("Can't remap registers");
|
pr_err("Can't remap registers\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = of_property_read_u32(node, "clock-frequency", &freq);
|
ret = of_property_read_u32(node, "clock-frequency", &freq);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Can't read clock-frequency");
|
pr_err("Can't read clock-frequency\n");
|
||||||
goto err_iounmap;
|
goto err_iounmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ static int __init bcm2835_timer_init(struct device_node *node)
|
|||||||
|
|
||||||
irq = irq_of_parse_and_map(node, DEFAULT_TIMER);
|
irq = irq_of_parse_and_map(node, DEFAULT_TIMER);
|
||||||
if (irq <= 0) {
|
if (irq <= 0) {
|
||||||
pr_err("Can't parse IRQ");
|
pr_err("Can't parse IRQ\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err_iounmap;
|
goto err_iounmap;
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,7 @@ static int __init kona_timer_init(struct device_node *node)
|
|||||||
} else if (!of_property_read_u32(node, "clock-frequency", &freq)) {
|
} else if (!of_property_read_u32(node, "clock-frequency", &freq)) {
|
||||||
arch_timer_rate = freq;
|
arch_timer_rate = freq;
|
||||||
} else {
|
} else {
|
||||||
pr_err("Kona Timer v1 unable to determine clock-frequency");
|
pr_err("Kona Timer v1 unable to determine clock-frequency\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ void __init clocksource_probe(void)
|
|||||||
|
|
||||||
ret = init_func_ret(np);
|
ret = init_func_ret(np);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to initialize '%s': %d",
|
pr_err("Failed to initialize '%s': %d\n",
|
||||||
of_node_full_name(np), ret);
|
of_node_full_name(np), ret);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
|
|||||||
struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
|
struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
|
||||||
|
|
||||||
if (!evt->event_handler) {
|
if (!evt->event_handler) {
|
||||||
pr_info("Spurious APBT timer interrupt %d", irq);
|
pr_info("Spurious APBT timer interrupt %d\n", irq);
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +257,9 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
|
|||||||
clockevents_calc_mult_shift(&dw_ced->ced, freq, APBT_MIN_PERIOD);
|
clockevents_calc_mult_shift(&dw_ced->ced, freq, APBT_MIN_PERIOD);
|
||||||
dw_ced->ced.max_delta_ns = clockevent_delta2ns(0x7fffffff,
|
dw_ced->ced.max_delta_ns = clockevent_delta2ns(0x7fffffff,
|
||||||
&dw_ced->ced);
|
&dw_ced->ced);
|
||||||
|
dw_ced->ced.max_delta_ticks = 0x7fffffff;
|
||||||
dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced);
|
dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced);
|
||||||
|
dw_ced->ced.min_delta_ticks = 5000;
|
||||||
dw_ced->ced.cpumask = cpumask_of(cpu);
|
dw_ced->ced.cpumask = cpumask_of(cpu);
|
||||||
dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC |
|
dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC |
|
||||||
CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
|
CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
|
||||||
|
@ -78,15 +78,12 @@ static int em_sti_enable(struct em_sti_priv *p)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* enable clock */
|
/* enable clock */
|
||||||
ret = clk_prepare_enable(p->clk);
|
ret = clk_enable(p->clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&p->pdev->dev, "cannot enable clock\n");
|
dev_err(&p->pdev->dev, "cannot enable clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* configure channel, periodic mode and maximum timeout */
|
|
||||||
p->rate = clk_get_rate(p->clk);
|
|
||||||
|
|
||||||
/* reset the counter */
|
/* reset the counter */
|
||||||
em_sti_write(p, STI_SET_H, 0x40000000);
|
em_sti_write(p, STI_SET_H, 0x40000000);
|
||||||
em_sti_write(p, STI_SET_L, 0x00000000);
|
em_sti_write(p, STI_SET_L, 0x00000000);
|
||||||
@ -107,7 +104,7 @@ static void em_sti_disable(struct em_sti_priv *p)
|
|||||||
em_sti_write(p, STI_INTENCLR, 3);
|
em_sti_write(p, STI_INTENCLR, 3);
|
||||||
|
|
||||||
/* stop clock */
|
/* stop clock */
|
||||||
clk_disable_unprepare(p->clk);
|
clk_disable(p->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 em_sti_count(struct em_sti_priv *p)
|
static u64 em_sti_count(struct em_sti_priv *p)
|
||||||
@ -205,13 +202,9 @@ static u64 em_sti_clocksource_read(struct clocksource *cs)
|
|||||||
|
|
||||||
static int em_sti_clocksource_enable(struct clocksource *cs)
|
static int em_sti_clocksource_enable(struct clocksource *cs)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
struct em_sti_priv *p = cs_to_em_sti(cs);
|
struct em_sti_priv *p = cs_to_em_sti(cs);
|
||||||
|
|
||||||
ret = em_sti_start(p, USER_CLOCKSOURCE);
|
return em_sti_start(p, USER_CLOCKSOURCE);
|
||||||
if (!ret)
|
|
||||||
__clocksource_update_freq_hz(cs, p->rate);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void em_sti_clocksource_disable(struct clocksource *cs)
|
static void em_sti_clocksource_disable(struct clocksource *cs)
|
||||||
@ -240,8 +233,7 @@ static int em_sti_register_clocksource(struct em_sti_priv *p)
|
|||||||
|
|
||||||
dev_info(&p->pdev->dev, "used as clock source\n");
|
dev_info(&p->pdev->dev, "used as clock source\n");
|
||||||
|
|
||||||
/* Register with dummy 1 Hz value, gets updated in ->enable() */
|
clocksource_register_hz(cs, p->rate);
|
||||||
clocksource_register_hz(cs, 1);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +255,6 @@ static int em_sti_clock_event_set_oneshot(struct clock_event_device *ced)
|
|||||||
|
|
||||||
dev_info(&p->pdev->dev, "used for oneshot clock events\n");
|
dev_info(&p->pdev->dev, "used for oneshot clock events\n");
|
||||||
em_sti_start(p, USER_CLOCKEVENT);
|
em_sti_start(p, USER_CLOCKEVENT);
|
||||||
clockevents_config(&p->ced, p->rate);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,8 +285,7 @@ static void em_sti_register_clockevent(struct em_sti_priv *p)
|
|||||||
|
|
||||||
dev_info(&p->pdev->dev, "used for clock events\n");
|
dev_info(&p->pdev->dev, "used for clock events\n");
|
||||||
|
|
||||||
/* Register with dummy 1 Hz value, gets updated in ->set_state_oneshot() */
|
clockevents_config_and_register(ced, p->rate, 2, 0xffffffff);
|
||||||
clockevents_config_and_register(ced, 1, 2, 0xffffffff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int em_sti_probe(struct platform_device *pdev)
|
static int em_sti_probe(struct platform_device *pdev)
|
||||||
@ -303,6 +293,7 @@ static int em_sti_probe(struct platform_device *pdev)
|
|||||||
struct em_sti_priv *p;
|
struct em_sti_priv *p;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int irq;
|
int irq;
|
||||||
|
int ret;
|
||||||
|
|
||||||
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
|
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
@ -323,6 +314,13 @@ static int em_sti_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(p->base))
|
if (IS_ERR(p->base))
|
||||||
return PTR_ERR(p->base);
|
return PTR_ERR(p->base);
|
||||||
|
|
||||||
|
if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt,
|
||||||
|
IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
|
||||||
|
dev_name(&pdev->dev), p)) {
|
||||||
|
dev_err(&pdev->dev, "failed to request low IRQ\n");
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
/* get hold of clock */
|
/* get hold of clock */
|
||||||
p->clk = devm_clk_get(&pdev->dev, "sclk");
|
p->clk = devm_clk_get(&pdev->dev, "sclk");
|
||||||
if (IS_ERR(p->clk)) {
|
if (IS_ERR(p->clk)) {
|
||||||
@ -330,13 +328,21 @@ static int em_sti_probe(struct platform_device *pdev)
|
|||||||
return PTR_ERR(p->clk);
|
return PTR_ERR(p->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt,
|
ret = clk_prepare(p->clk);
|
||||||
IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
|
if (ret < 0) {
|
||||||
dev_name(&pdev->dev), p)) {
|
dev_err(&pdev->dev, "cannot prepare clock\n");
|
||||||
dev_err(&pdev->dev, "failed to request low IRQ\n");
|
return ret;
|
||||||
return -ENOENT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = clk_enable(p->clk);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&p->pdev->dev, "cannot enable clock\n");
|
||||||
|
clk_unprepare(p->clk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
p->rate = clk_get_rate(p->clk);
|
||||||
|
clk_disable(p->clk);
|
||||||
|
|
||||||
raw_spin_lock_init(&p->lock);
|
raw_spin_lock_init(&p->lock);
|
||||||
em_sti_register_clockevent(p);
|
em_sti_register_clockevent(p);
|
||||||
em_sti_register_clocksource(p);
|
em_sti_register_clocksource(p);
|
||||||
|
@ -101,15 +101,7 @@ static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
|
|||||||
|
|
||||||
static void timer8_clock_event_start(struct timer8_priv *p, unsigned long delta)
|
static void timer8_clock_event_start(struct timer8_priv *p, unsigned long delta)
|
||||||
{
|
{
|
||||||
struct clock_event_device *ced = &p->ced;
|
|
||||||
|
|
||||||
timer8_start(p);
|
timer8_start(p);
|
||||||
|
|
||||||
ced->shift = 32;
|
|
||||||
ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift);
|
|
||||||
ced->max_delta_ns = clockevent_delta2ns(0xffff, ced);
|
|
||||||
ced->min_delta_ns = clockevent_delta2ns(0x0001, ced);
|
|
||||||
|
|
||||||
timer8_set_next(p, delta);
|
timer8_set_next(p, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,13 +133,13 @@ static int __init meson6_timer_init(struct device_node *node)
|
|||||||
|
|
||||||
timer_base = of_io_request_and_map(node, 0, "meson6-timer");
|
timer_base = of_io_request_and_map(node, 0, "meson6-timer");
|
||||||
if (IS_ERR(timer_base)) {
|
if (IS_ERR(timer_base)) {
|
||||||
pr_err("Can't map registers");
|
pr_err("Can't map registers\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = irq_of_parse_and_map(node, 0);
|
irq = irq_of_parse_and_map(node, 0);
|
||||||
if (irq <= 0) {
|
if (irq <= 0) {
|
||||||
pr_err("Can't parse IRQ");
|
pr_err("Can't parse IRQ\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,9 @@ static int arch_timer_starting_cpu(unsigned int cpu)
|
|||||||
|
|
||||||
clk->mult = div_sc(hwtimer_freq, NSEC_PER_SEC, clk->shift);
|
clk->mult = div_sc(hwtimer_freq, NSEC_PER_SEC, clk->shift);
|
||||||
clk->max_delta_ns = clockevent_delta2ns(0x7fffffff, clk);
|
clk->max_delta_ns = clockevent_delta2ns(0x7fffffff, clk);
|
||||||
|
clk->max_delta_ticks = 0x7fffffff;
|
||||||
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
|
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
|
||||||
|
clk->min_delta_ticks = 0xf;
|
||||||
clk->cpumask = cpumask_of(cpu);
|
clk->cpumask = cpumask_of(cpu);
|
||||||
|
|
||||||
clockevents_register_device(clk);
|
clockevents_register_device(clk);
|
||||||
|
@ -154,19 +154,6 @@ static int __init __gic_clocksource_init(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init gic_clocksource_init(unsigned int frequency)
|
|
||||||
{
|
|
||||||
gic_frequency = frequency;
|
|
||||||
gic_timer_irq = MIPS_GIC_IRQ_BASE +
|
|
||||||
GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE);
|
|
||||||
|
|
||||||
__gic_clocksource_init();
|
|
||||||
gic_clockevent_init();
|
|
||||||
|
|
||||||
/* And finally start the counter */
|
|
||||||
gic_start_count();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init gic_clocksource_of_init(struct device_node *node)
|
static int __init gic_clocksource_of_init(struct device_node *node)
|
||||||
{
|
{
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
@ -174,7 +161,7 @@ static int __init gic_clocksource_of_init(struct device_node *node)
|
|||||||
|
|
||||||
if (!gic_present || !node->parent ||
|
if (!gic_present || !node->parent ||
|
||||||
!of_device_is_compatible(node->parent, "mti,gic")) {
|
!of_device_is_compatible(node->parent, "mti,gic")) {
|
||||||
pr_warn("No DT definition for the mips gic driver");
|
pr_warn("No DT definition for the mips gic driver\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,25 +260,25 @@ static int __init nmdk_timer_of_init(struct device_node *node)
|
|||||||
|
|
||||||
base = of_iomap(node, 0);
|
base = of_iomap(node, 0);
|
||||||
if (!base) {
|
if (!base) {
|
||||||
pr_err("Can't remap registers");
|
pr_err("Can't remap registers\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
pclk = of_clk_get_by_name(node, "apb_pclk");
|
pclk = of_clk_get_by_name(node, "apb_pclk");
|
||||||
if (IS_ERR(pclk)) {
|
if (IS_ERR(pclk)) {
|
||||||
pr_err("could not get apb_pclk");
|
pr_err("could not get apb_pclk\n");
|
||||||
return PTR_ERR(pclk);
|
return PTR_ERR(pclk);
|
||||||
}
|
}
|
||||||
|
|
||||||
clk = of_clk_get_by_name(node, "timclk");
|
clk = of_clk_get_by_name(node, "timclk");
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
pr_err("could not get timclk");
|
pr_err("could not get timclk\n");
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = irq_of_parse_and_map(node, 0);
|
irq = irq_of_parse_and_map(node, 0);
|
||||||
if (irq <= 0) {
|
if (irq <= 0) {
|
||||||
pr_err("Can't parse IRQ");
|
pr_err("Can't parse IRQ\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,9 @@ static struct clock_event_device numachip2_clockevent = {
|
|||||||
.mult = 1,
|
.mult = 1,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
.min_delta_ns = 1250,
|
.min_delta_ns = 1250,
|
||||||
|
.min_delta_ticks = 1250,
|
||||||
.max_delta_ns = LONG_MAX,
|
.max_delta_ns = LONG_MAX,
|
||||||
|
.max_delta_ticks = LONG_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void numachip_timer_interrupt(void)
|
static void numachip_timer_interrupt(void)
|
||||||
|
@ -166,14 +166,14 @@ static int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
|
|||||||
|
|
||||||
ret = setup_irq(irq, &pxa_ost0_irq);
|
ret = setup_irq(irq, &pxa_ost0_irq);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to setup irq");
|
pr_err("Failed to setup irq\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200,
|
ret = clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200,
|
||||||
32, clocksource_mmio_readl_up);
|
32, clocksource_mmio_readl_up);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to init clocksource");
|
pr_err("Failed to init clocksource\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ static int __init pxa_timer_dt_init(struct device_node *np)
|
|||||||
|
|
||||||
ret = clk_prepare_enable(clk);
|
ret = clk_prepare_enable(clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_crit("Failed to prepare clock");
|
pr_crit("Failed to prepare clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include <linux/clockchips.h>
|
#include <linux/clockchips.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/sched_clock.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
@ -19,6 +21,8 @@
|
|||||||
|
|
||||||
#define TIMER_LOAD_COUNT0 0x00
|
#define TIMER_LOAD_COUNT0 0x00
|
||||||
#define TIMER_LOAD_COUNT1 0x04
|
#define TIMER_LOAD_COUNT1 0x04
|
||||||
|
#define TIMER_CURRENT_VALUE0 0x08
|
||||||
|
#define TIMER_CURRENT_VALUE1 0x0C
|
||||||
#define TIMER_CONTROL_REG3288 0x10
|
#define TIMER_CONTROL_REG3288 0x10
|
||||||
#define TIMER_CONTROL_REG3399 0x1c
|
#define TIMER_CONTROL_REG3399 0x1c
|
||||||
#define TIMER_INT_STATUS 0x18
|
#define TIMER_INT_STATUS 0x18
|
||||||
@ -29,103 +33,118 @@
|
|||||||
#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
|
#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
|
||||||
#define TIMER_INT_UNMASK (1 << 2)
|
#define TIMER_INT_UNMASK (1 << 2)
|
||||||
|
|
||||||
struct bc_timer {
|
struct rk_timer {
|
||||||
struct clock_event_device ce;
|
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
void __iomem *ctrl;
|
void __iomem *ctrl;
|
||||||
|
struct clk *clk;
|
||||||
|
struct clk *pclk;
|
||||||
u32 freq;
|
u32 freq;
|
||||||
|
int irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct bc_timer bc_timer;
|
struct rk_clkevt {
|
||||||
|
struct clock_event_device ce;
|
||||||
|
struct rk_timer timer;
|
||||||
|
};
|
||||||
|
|
||||||
static inline struct bc_timer *rk_timer(struct clock_event_device *ce)
|
static struct rk_clkevt *rk_clkevt;
|
||||||
|
static struct rk_timer *rk_clksrc;
|
||||||
|
|
||||||
|
static inline struct rk_timer *rk_timer(struct clock_event_device *ce)
|
||||||
{
|
{
|
||||||
return container_of(ce, struct bc_timer, ce);
|
return &container_of(ce, struct rk_clkevt, ce)->timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __iomem *rk_base(struct clock_event_device *ce)
|
static inline void rk_timer_disable(struct rk_timer *timer)
|
||||||
{
|
{
|
||||||
return rk_timer(ce)->base;
|
writel_relaxed(TIMER_DISABLE, timer->ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __iomem *rk_ctrl(struct clock_event_device *ce)
|
static inline void rk_timer_enable(struct rk_timer *timer, u32 flags)
|
||||||
{
|
{
|
||||||
return rk_timer(ce)->ctrl;
|
writel_relaxed(TIMER_ENABLE | flags, timer->ctrl);
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rk_timer_disable(struct clock_event_device *ce)
|
|
||||||
{
|
|
||||||
writel_relaxed(TIMER_DISABLE, rk_ctrl(ce));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags)
|
|
||||||
{
|
|
||||||
writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
|
|
||||||
rk_ctrl(ce));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rk_timer_update_counter(unsigned long cycles,
|
static void rk_timer_update_counter(unsigned long cycles,
|
||||||
struct clock_event_device *ce)
|
struct rk_timer *timer)
|
||||||
{
|
{
|
||||||
writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0);
|
writel_relaxed(cycles, timer->base + TIMER_LOAD_COUNT0);
|
||||||
writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1);
|
writel_relaxed(0, timer->base + TIMER_LOAD_COUNT1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rk_timer_interrupt_clear(struct clock_event_device *ce)
|
static void rk_timer_interrupt_clear(struct rk_timer *timer)
|
||||||
{
|
{
|
||||||
writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS);
|
writel_relaxed(1, timer->base + TIMER_INT_STATUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int rk_timer_set_next_event(unsigned long cycles,
|
static inline int rk_timer_set_next_event(unsigned long cycles,
|
||||||
struct clock_event_device *ce)
|
struct clock_event_device *ce)
|
||||||
{
|
{
|
||||||
rk_timer_disable(ce);
|
struct rk_timer *timer = rk_timer(ce);
|
||||||
rk_timer_update_counter(cycles, ce);
|
|
||||||
rk_timer_enable(ce, TIMER_MODE_USER_DEFINED_COUNT);
|
rk_timer_disable(timer);
|
||||||
|
rk_timer_update_counter(cycles, timer);
|
||||||
|
rk_timer_enable(timer, TIMER_MODE_USER_DEFINED_COUNT |
|
||||||
|
TIMER_INT_UNMASK);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rk_timer_shutdown(struct clock_event_device *ce)
|
static int rk_timer_shutdown(struct clock_event_device *ce)
|
||||||
{
|
{
|
||||||
rk_timer_disable(ce);
|
struct rk_timer *timer = rk_timer(ce);
|
||||||
|
|
||||||
|
rk_timer_disable(timer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rk_timer_set_periodic(struct clock_event_device *ce)
|
static int rk_timer_set_periodic(struct clock_event_device *ce)
|
||||||
{
|
{
|
||||||
rk_timer_disable(ce);
|
struct rk_timer *timer = rk_timer(ce);
|
||||||
rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce);
|
|
||||||
rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING);
|
rk_timer_disable(timer);
|
||||||
|
rk_timer_update_counter(timer->freq / HZ - 1, timer);
|
||||||
|
rk_timer_enable(timer, TIMER_MODE_FREE_RUNNING | TIMER_INT_UNMASK);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
|
static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct clock_event_device *ce = dev_id;
|
struct clock_event_device *ce = dev_id;
|
||||||
|
struct rk_timer *timer = rk_timer(ce);
|
||||||
|
|
||||||
rk_timer_interrupt_clear(ce);
|
rk_timer_interrupt_clear(timer);
|
||||||
|
|
||||||
if (clockevent_state_oneshot(ce))
|
if (clockevent_state_oneshot(ce))
|
||||||
rk_timer_disable(ce);
|
rk_timer_disable(timer);
|
||||||
|
|
||||||
ce->event_handler(ce);
|
ce->event_handler(ce);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg)
|
static u64 notrace rk_timer_sched_read(void)
|
||||||
|
{
|
||||||
|
return ~readl_relaxed(rk_clksrc->base + TIMER_CURRENT_VALUE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init
|
||||||
|
rk_timer_probe(struct rk_timer *timer, struct device_node *np)
|
||||||
{
|
{
|
||||||
struct clock_event_device *ce = &bc_timer.ce;
|
|
||||||
struct clk *timer_clk;
|
struct clk *timer_clk;
|
||||||
struct clk *pclk;
|
struct clk *pclk;
|
||||||
int ret = -EINVAL, irq;
|
int ret = -EINVAL, irq;
|
||||||
|
u32 ctrl_reg = TIMER_CONTROL_REG3288;
|
||||||
|
|
||||||
bc_timer.base = of_iomap(np, 0);
|
timer->base = of_iomap(np, 0);
|
||||||
if (!bc_timer.base) {
|
if (!timer->base) {
|
||||||
pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
|
pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
bc_timer.ctrl = bc_timer.base + ctrl_reg;
|
|
||||||
|
if (of_device_is_compatible(np, "rockchip,rk3399-timer"))
|
||||||
|
ctrl_reg = TIMER_CONTROL_REG3399;
|
||||||
|
|
||||||
|
timer->ctrl = timer->base + ctrl_reg;
|
||||||
|
|
||||||
pclk = of_clk_get_by_name(np, "pclk");
|
pclk = of_clk_get_by_name(np, "pclk");
|
||||||
if (IS_ERR(pclk)) {
|
if (IS_ERR(pclk)) {
|
||||||
@ -139,6 +158,7 @@ static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg)
|
|||||||
pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
|
pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
|
||||||
goto out_unmap;
|
goto out_unmap;
|
||||||
}
|
}
|
||||||
|
timer->pclk = pclk;
|
||||||
|
|
||||||
timer_clk = of_clk_get_by_name(np, "timer");
|
timer_clk = of_clk_get_by_name(np, "timer");
|
||||||
if (IS_ERR(timer_clk)) {
|
if (IS_ERR(timer_clk)) {
|
||||||
@ -152,8 +172,9 @@ static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg)
|
|||||||
pr_err("Failed to enable timer clock\n");
|
pr_err("Failed to enable timer clock\n");
|
||||||
goto out_timer_clk;
|
goto out_timer_clk;
|
||||||
}
|
}
|
||||||
|
timer->clk = timer_clk;
|
||||||
|
|
||||||
bc_timer.freq = clk_get_rate(timer_clk);
|
timer->freq = clk_get_rate(timer_clk);
|
||||||
|
|
||||||
irq = irq_of_parse_and_map(np, 0);
|
irq = irq_of_parse_and_map(np, 0);
|
||||||
if (!irq) {
|
if (!irq) {
|
||||||
@ -161,28 +182,10 @@ static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg)
|
|||||||
pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
|
pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
|
||||||
goto out_irq;
|
goto out_irq;
|
||||||
}
|
}
|
||||||
|
timer->irq = irq;
|
||||||
|
|
||||||
ce->name = TIMER_NAME;
|
rk_timer_interrupt_clear(timer);
|
||||||
ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
|
rk_timer_disable(timer);
|
||||||
CLOCK_EVT_FEAT_DYNIRQ;
|
|
||||||
ce->set_next_event = rk_timer_set_next_event;
|
|
||||||
ce->set_state_shutdown = rk_timer_shutdown;
|
|
||||||
ce->set_state_periodic = rk_timer_set_periodic;
|
|
||||||
ce->irq = irq;
|
|
||||||
ce->cpumask = cpu_possible_mask;
|
|
||||||
ce->rating = 250;
|
|
||||||
|
|
||||||
rk_timer_interrupt_clear(ce);
|
|
||||||
rk_timer_disable(ce);
|
|
||||||
|
|
||||||
ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
|
|
||||||
goto out_irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_irq:
|
out_irq:
|
||||||
@ -190,22 +193,115 @@ out_irq:
|
|||||||
out_timer_clk:
|
out_timer_clk:
|
||||||
clk_disable_unprepare(pclk);
|
clk_disable_unprepare(pclk);
|
||||||
out_unmap:
|
out_unmap:
|
||||||
iounmap(bc_timer.base);
|
iounmap(timer->base);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init rk3288_timer_init(struct device_node *np)
|
static void __init rk_timer_cleanup(struct rk_timer *timer)
|
||||||
{
|
{
|
||||||
return rk_timer_init(np, TIMER_CONTROL_REG3288);
|
clk_disable_unprepare(timer->clk);
|
||||||
|
clk_disable_unprepare(timer->pclk);
|
||||||
|
iounmap(timer->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init rk3399_timer_init(struct device_node *np)
|
static int __init rk_clkevt_init(struct device_node *np)
|
||||||
{
|
{
|
||||||
return rk_timer_init(np, TIMER_CONTROL_REG3399);
|
struct clock_event_device *ce;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
rk_clkevt = kzalloc(sizeof(struct rk_clkevt), GFP_KERNEL);
|
||||||
|
if (!rk_clkevt) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rk_timer_probe(&rk_clkevt->timer, np);
|
||||||
|
if (ret)
|
||||||
|
goto out_probe;
|
||||||
|
|
||||||
|
ce = &rk_clkevt->ce;
|
||||||
|
ce->name = TIMER_NAME;
|
||||||
|
ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
|
||||||
|
CLOCK_EVT_FEAT_DYNIRQ;
|
||||||
|
ce->set_next_event = rk_timer_set_next_event;
|
||||||
|
ce->set_state_shutdown = rk_timer_shutdown;
|
||||||
|
ce->set_state_periodic = rk_timer_set_periodic;
|
||||||
|
ce->irq = rk_clkevt->timer.irq;
|
||||||
|
ce->cpumask = cpu_possible_mask;
|
||||||
|
ce->rating = 250;
|
||||||
|
|
||||||
|
ret = request_irq(rk_clkevt->timer.irq, rk_timer_interrupt, IRQF_TIMER,
|
||||||
|
TIMER_NAME, ce);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Failed to initialize '%s': %d\n",
|
||||||
|
TIMER_NAME, ret);
|
||||||
|
goto out_irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
clockevents_config_and_register(&rk_clkevt->ce,
|
||||||
|
rk_clkevt->timer.freq, 1, UINT_MAX);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_irq:
|
||||||
|
rk_timer_cleanup(&rk_clkevt->timer);
|
||||||
|
out_probe:
|
||||||
|
kfree(rk_clkevt);
|
||||||
|
out:
|
||||||
|
/* Leave rk_clkevt not NULL to prevent future init */
|
||||||
|
rk_clkevt = ERR_PTR(ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer",
|
static int __init rk_clksrc_init(struct device_node *np)
|
||||||
rk3288_timer_init);
|
{
|
||||||
CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer",
|
int ret = -EINVAL;
|
||||||
rk3399_timer_init);
|
|
||||||
|
rk_clksrc = kzalloc(sizeof(struct rk_timer), GFP_KERNEL);
|
||||||
|
if (!rk_clksrc) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rk_timer_probe(rk_clksrc, np);
|
||||||
|
if (ret)
|
||||||
|
goto out_probe;
|
||||||
|
|
||||||
|
rk_timer_update_counter(UINT_MAX, rk_clksrc);
|
||||||
|
rk_timer_enable(rk_clksrc, 0);
|
||||||
|
|
||||||
|
ret = clocksource_mmio_init(rk_clksrc->base + TIMER_CURRENT_VALUE0,
|
||||||
|
TIMER_NAME, rk_clksrc->freq, 250, 32,
|
||||||
|
clocksource_mmio_readl_down);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Failed to register clocksource");
|
||||||
|
goto out_clocksource;
|
||||||
|
}
|
||||||
|
|
||||||
|
sched_clock_register(rk_timer_sched_read, 32, rk_clksrc->freq);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_clocksource:
|
||||||
|
rk_timer_cleanup(rk_clksrc);
|
||||||
|
out_probe:
|
||||||
|
kfree(rk_clksrc);
|
||||||
|
out:
|
||||||
|
/* Leave rk_clksrc not NULL to prevent future init */
|
||||||
|
rk_clksrc = ERR_PTR(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init rk_timer_init(struct device_node *np)
|
||||||
|
{
|
||||||
|
if (!rk_clkevt)
|
||||||
|
return rk_clkevt_init(np);
|
||||||
|
|
||||||
|
if (!rk_clksrc)
|
||||||
|
return rk_clksrc_init(np);
|
||||||
|
|
||||||
|
pr_err("Too many timer definitions for '%s'\n", TIMER_NAME);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", rk_timer_init);
|
||||||
|
CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", rk_timer_init);
|
||||||
|
@ -385,7 +385,7 @@ static int __init _samsung_pwm_clocksource_init(void)
|
|||||||
mask = ~pwm.variant.output_mask & ((1 << SAMSUNG_PWM_NUM) - 1);
|
mask = ~pwm.variant.output_mask & ((1 << SAMSUNG_PWM_NUM) - 1);
|
||||||
channel = fls(mask) - 1;
|
channel = fls(mask) - 1;
|
||||||
if (channel < 0) {
|
if (channel < 0) {
|
||||||
pr_crit("failed to find PWM channel for clocksource");
|
pr_crit("failed to find PWM channel for clocksource\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
pwm.source_id = channel;
|
pwm.source_id = channel;
|
||||||
@ -393,7 +393,7 @@ static int __init _samsung_pwm_clocksource_init(void)
|
|||||||
mask &= ~(1 << channel);
|
mask &= ~(1 << channel);
|
||||||
channel = fls(mask) - 1;
|
channel = fls(mask) - 1;
|
||||||
if (channel < 0) {
|
if (channel < 0) {
|
||||||
pr_crit("failed to find PWM channel for clock event");
|
pr_crit("failed to find PWM channel for clock event\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
pwm.event_id = channel;
|
pwm.event_id = channel;
|
||||||
@ -448,7 +448,7 @@ static int __init samsung_pwm_alloc(struct device_node *np,
|
|||||||
|
|
||||||
pwm.timerclk = of_clk_get_by_name(np, "timers");
|
pwm.timerclk = of_clk_get_by_name(np, "timers");
|
||||||
if (IS_ERR(pwm.timerclk)) {
|
if (IS_ERR(pwm.timerclk)) {
|
||||||
pr_crit("failed to get timers clock for timer");
|
pr_crit("failed to get timers clock for timer\n");
|
||||||
return PTR_ERR(pwm.timerclk);
|
return PTR_ERR(pwm.timerclk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,6 @@ struct sh_cmt_channel {
|
|||||||
unsigned long match_value;
|
unsigned long match_value;
|
||||||
unsigned long next_match_value;
|
unsigned long next_match_value;
|
||||||
unsigned long max_match_value;
|
unsigned long max_match_value;
|
||||||
unsigned long rate;
|
|
||||||
raw_spinlock_t lock;
|
raw_spinlock_t lock;
|
||||||
struct clock_event_device ced;
|
struct clock_event_device ced;
|
||||||
struct clocksource cs;
|
struct clocksource cs;
|
||||||
@ -118,6 +117,7 @@ struct sh_cmt_device {
|
|||||||
|
|
||||||
void __iomem *mapbase;
|
void __iomem *mapbase;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
unsigned long rate;
|
||||||
|
|
||||||
raw_spinlock_t lock; /* Protect the shared start/stop register */
|
raw_spinlock_t lock; /* Protect the shared start/stop register */
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
|
|||||||
raw_spin_unlock_irqrestore(&ch->cmt->lock, flags);
|
raw_spin_unlock_irqrestore(&ch->cmt->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)
|
static int sh_cmt_enable(struct sh_cmt_channel *ch)
|
||||||
{
|
{
|
||||||
int k, ret;
|
int k, ret;
|
||||||
|
|
||||||
@ -340,11 +340,9 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)
|
|||||||
|
|
||||||
/* configure channel, periodic mode and maximum timeout */
|
/* configure channel, periodic mode and maximum timeout */
|
||||||
if (ch->cmt->info->width == 16) {
|
if (ch->cmt->info->width == 16) {
|
||||||
*rate = clk_get_rate(ch->cmt->clk) / 512;
|
|
||||||
sh_cmt_write_cmcsr(ch, SH_CMT16_CMCSR_CMIE |
|
sh_cmt_write_cmcsr(ch, SH_CMT16_CMCSR_CMIE |
|
||||||
SH_CMT16_CMCSR_CKS512);
|
SH_CMT16_CMCSR_CKS512);
|
||||||
} else {
|
} else {
|
||||||
*rate = clk_get_rate(ch->cmt->clk) / 8;
|
|
||||||
sh_cmt_write_cmcsr(ch, SH_CMT32_CMCSR_CMM |
|
sh_cmt_write_cmcsr(ch, SH_CMT32_CMCSR_CMM |
|
||||||
SH_CMT32_CMCSR_CMTOUT_IE |
|
SH_CMT32_CMCSR_CMTOUT_IE |
|
||||||
SH_CMT32_CMCSR_CMR_IRQ |
|
SH_CMT32_CMCSR_CMR_IRQ |
|
||||||
@ -572,7 +570,7 @@ static int sh_cmt_start(struct sh_cmt_channel *ch, unsigned long flag)
|
|||||||
raw_spin_lock_irqsave(&ch->lock, flags);
|
raw_spin_lock_irqsave(&ch->lock, flags);
|
||||||
|
|
||||||
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
|
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
|
||||||
ret = sh_cmt_enable(ch, &ch->rate);
|
ret = sh_cmt_enable(ch);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
@ -640,10 +638,9 @@ static int sh_cmt_clocksource_enable(struct clocksource *cs)
|
|||||||
ch->total_cycles = 0;
|
ch->total_cycles = 0;
|
||||||
|
|
||||||
ret = sh_cmt_start(ch, FLAG_CLOCKSOURCE);
|
ret = sh_cmt_start(ch, FLAG_CLOCKSOURCE);
|
||||||
if (!ret) {
|
if (!ret)
|
||||||
__clocksource_update_freq_hz(cs, ch->rate);
|
|
||||||
ch->cs_enabled = true;
|
ch->cs_enabled = true;
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -697,8 +694,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_channel *ch,
|
|||||||
dev_info(&ch->cmt->pdev->dev, "ch%u: used as clock source\n",
|
dev_info(&ch->cmt->pdev->dev, "ch%u: used as clock source\n",
|
||||||
ch->index);
|
ch->index);
|
||||||
|
|
||||||
/* Register with dummy 1 Hz value, gets updated in ->enable() */
|
clocksource_register_hz(cs, ch->cmt->rate);
|
||||||
clocksource_register_hz(cs, 1);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,19 +705,10 @@ static struct sh_cmt_channel *ced_to_sh_cmt(struct clock_event_device *ced)
|
|||||||
|
|
||||||
static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic)
|
static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic)
|
||||||
{
|
{
|
||||||
struct clock_event_device *ced = &ch->ced;
|
|
||||||
|
|
||||||
sh_cmt_start(ch, FLAG_CLOCKEVENT);
|
sh_cmt_start(ch, FLAG_CLOCKEVENT);
|
||||||
|
|
||||||
/* TODO: calculate good shift from rate and counter bit width */
|
|
||||||
|
|
||||||
ced->shift = 32;
|
|
||||||
ced->mult = div_sc(ch->rate, NSEC_PER_SEC, ced->shift);
|
|
||||||
ced->max_delta_ns = clockevent_delta2ns(ch->max_match_value, ced);
|
|
||||||
ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
|
|
||||||
|
|
||||||
if (periodic)
|
if (periodic)
|
||||||
sh_cmt_set_next(ch, ((ch->rate + HZ/2) / HZ) - 1);
|
sh_cmt_set_next(ch, ((ch->cmt->rate + HZ/2) / HZ) - 1);
|
||||||
else
|
else
|
||||||
sh_cmt_set_next(ch, ch->max_match_value);
|
sh_cmt_set_next(ch, ch->max_match_value);
|
||||||
}
|
}
|
||||||
@ -824,6 +811,14 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch,
|
|||||||
ced->suspend = sh_cmt_clock_event_suspend;
|
ced->suspend = sh_cmt_clock_event_suspend;
|
||||||
ced->resume = sh_cmt_clock_event_resume;
|
ced->resume = sh_cmt_clock_event_resume;
|
||||||
|
|
||||||
|
/* TODO: calculate good shift from rate and counter bit width */
|
||||||
|
ced->shift = 32;
|
||||||
|
ced->mult = div_sc(ch->cmt->rate, NSEC_PER_SEC, ced->shift);
|
||||||
|
ced->max_delta_ns = clockevent_delta2ns(ch->max_match_value, ced);
|
||||||
|
ced->max_delta_ticks = ch->max_match_value;
|
||||||
|
ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
|
||||||
|
ced->min_delta_ticks = 0x1f;
|
||||||
|
|
||||||
dev_info(&ch->cmt->pdev->dev, "ch%u: used for clock events\n",
|
dev_info(&ch->cmt->pdev->dev, "ch%u: used for clock events\n",
|
||||||
ch->index);
|
ch->index);
|
||||||
clockevents_register_device(ced);
|
clockevents_register_device(ced);
|
||||||
@ -996,6 +991,18 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_clk_put;
|
goto err_clk_put;
|
||||||
|
|
||||||
|
/* Determine clock rate. */
|
||||||
|
ret = clk_enable(cmt->clk);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err_clk_unprepare;
|
||||||
|
|
||||||
|
if (cmt->info->width == 16)
|
||||||
|
cmt->rate = clk_get_rate(cmt->clk) / 512;
|
||||||
|
else
|
||||||
|
cmt->rate = clk_get_rate(cmt->clk) / 8;
|
||||||
|
|
||||||
|
clk_disable(cmt->clk);
|
||||||
|
|
||||||
/* Map the memory resource(s). */
|
/* Map the memory resource(s). */
|
||||||
ret = sh_cmt_map_memory(cmt);
|
ret = sh_cmt_map_memory(cmt);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -46,7 +46,6 @@ struct sh_tmu_channel {
|
|||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
unsigned long rate;
|
|
||||||
unsigned long periodic;
|
unsigned long periodic;
|
||||||
struct clock_event_device ced;
|
struct clock_event_device ced;
|
||||||
struct clocksource cs;
|
struct clocksource cs;
|
||||||
@ -59,6 +58,7 @@ struct sh_tmu_device {
|
|||||||
|
|
||||||
void __iomem *mapbase;
|
void __iomem *mapbase;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
unsigned long rate;
|
||||||
|
|
||||||
enum sh_tmu_model model;
|
enum sh_tmu_model model;
|
||||||
|
|
||||||
@ -165,7 +165,6 @@ static int __sh_tmu_enable(struct sh_tmu_channel *ch)
|
|||||||
sh_tmu_write(ch, TCNT, 0xffffffff);
|
sh_tmu_write(ch, TCNT, 0xffffffff);
|
||||||
|
|
||||||
/* configure channel to parent clock / 4, irq off */
|
/* configure channel to parent clock / 4, irq off */
|
||||||
ch->rate = clk_get_rate(ch->tmu->clk) / 4;
|
|
||||||
sh_tmu_write(ch, TCR, TCR_TPSC_CLK4);
|
sh_tmu_write(ch, TCR, TCR_TPSC_CLK4);
|
||||||
|
|
||||||
/* enable channel */
|
/* enable channel */
|
||||||
@ -271,10 +270,8 @@ static int sh_tmu_clocksource_enable(struct clocksource *cs)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = sh_tmu_enable(ch);
|
ret = sh_tmu_enable(ch);
|
||||||
if (!ret) {
|
if (!ret)
|
||||||
__clocksource_update_freq_hz(cs, ch->rate);
|
|
||||||
ch->cs_enabled = true;
|
ch->cs_enabled = true;
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -334,8 +331,7 @@ static int sh_tmu_register_clocksource(struct sh_tmu_channel *ch,
|
|||||||
dev_info(&ch->tmu->pdev->dev, "ch%u: used as clock source\n",
|
dev_info(&ch->tmu->pdev->dev, "ch%u: used as clock source\n",
|
||||||
ch->index);
|
ch->index);
|
||||||
|
|
||||||
/* Register with dummy 1 Hz value, gets updated in ->enable() */
|
clocksource_register_hz(cs, ch->tmu->rate);
|
||||||
clocksource_register_hz(cs, 1);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,14 +342,10 @@ static struct sh_tmu_channel *ced_to_sh_tmu(struct clock_event_device *ced)
|
|||||||
|
|
||||||
static void sh_tmu_clock_event_start(struct sh_tmu_channel *ch, int periodic)
|
static void sh_tmu_clock_event_start(struct sh_tmu_channel *ch, int periodic)
|
||||||
{
|
{
|
||||||
struct clock_event_device *ced = &ch->ced;
|
|
||||||
|
|
||||||
sh_tmu_enable(ch);
|
sh_tmu_enable(ch);
|
||||||
|
|
||||||
clockevents_config(ced, ch->rate);
|
|
||||||
|
|
||||||
if (periodic) {
|
if (periodic) {
|
||||||
ch->periodic = (ch->rate + HZ/2) / HZ;
|
ch->periodic = (ch->tmu->rate + HZ/2) / HZ;
|
||||||
sh_tmu_set_next(ch, ch->periodic, 1);
|
sh_tmu_set_next(ch, ch->periodic, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -435,7 +427,7 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch,
|
|||||||
dev_info(&ch->tmu->pdev->dev, "ch%u: used for clock events\n",
|
dev_info(&ch->tmu->pdev->dev, "ch%u: used for clock events\n",
|
||||||
ch->index);
|
ch->index);
|
||||||
|
|
||||||
clockevents_config_and_register(ced, 1, 0x300, 0xffffffff);
|
clockevents_config_and_register(ced, ch->tmu->rate, 0x300, 0xffffffff);
|
||||||
|
|
||||||
ret = request_irq(ch->irq, sh_tmu_interrupt,
|
ret = request_irq(ch->irq, sh_tmu_interrupt,
|
||||||
IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
|
IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
|
||||||
@ -561,6 +553,14 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_clk_put;
|
goto err_clk_put;
|
||||||
|
|
||||||
|
/* Determine clock rate. */
|
||||||
|
ret = clk_enable(tmu->clk);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err_clk_unprepare;
|
||||||
|
|
||||||
|
tmu->rate = clk_get_rate(tmu->clk) / 4;
|
||||||
|
clk_disable(tmu->clk);
|
||||||
|
|
||||||
/* Map the memory resource. */
|
/* Map the memory resource. */
|
||||||
ret = sh_tmu_map_memory(tmu);
|
ret = sh_tmu_map_memory(tmu);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -159,25 +159,25 @@ static int __init sun4i_timer_init(struct device_node *node)
|
|||||||
|
|
||||||
timer_base = of_iomap(node, 0);
|
timer_base = of_iomap(node, 0);
|
||||||
if (!timer_base) {
|
if (!timer_base) {
|
||||||
pr_crit("Can't map registers");
|
pr_crit("Can't map registers\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = irq_of_parse_and_map(node, 0);
|
irq = irq_of_parse_and_map(node, 0);
|
||||||
if (irq <= 0) {
|
if (irq <= 0) {
|
||||||
pr_crit("Can't parse IRQ");
|
pr_crit("Can't parse IRQ\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
clk = of_clk_get(node, 0);
|
clk = of_clk_get(node, 0);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
pr_crit("Can't get timer clock");
|
pr_crit("Can't get timer clock\n");
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_prepare_enable(clk);
|
ret = clk_prepare_enable(clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to prepare clock");
|
pr_err("Failed to prepare clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ static int __init sun4i_timer_init(struct device_node *node)
|
|||||||
ret = clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name,
|
ret = clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name,
|
||||||
rate, 350, 32, clocksource_mmio_readl_down);
|
rate, 350, 32, clocksource_mmio_readl_down);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to register clocksource");
|
pr_err("Failed to register clocksource\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ static int __init tegra20_init_rtc(struct device_node *np)
|
|||||||
|
|
||||||
rtc_base = of_iomap(np, 0);
|
rtc_base = of_iomap(np, 0);
|
||||||
if (!rtc_base) {
|
if (!rtc_base) {
|
||||||
pr_err("Can't map RTC registers");
|
pr_err("Can't map RTC registers\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,13 +247,13 @@ static int __init armada_370_xp_timer_common_init(struct device_node *np)
|
|||||||
|
|
||||||
timer_base = of_iomap(np, 0);
|
timer_base = of_iomap(np, 0);
|
||||||
if (!timer_base) {
|
if (!timer_base) {
|
||||||
pr_err("Failed to iomap");
|
pr_err("Failed to iomap\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
local_base = of_iomap(np, 1);
|
local_base = of_iomap(np, 1);
|
||||||
if (!local_base) {
|
if (!local_base) {
|
||||||
pr_err("Failed to iomap");
|
pr_err("Failed to iomap\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +298,7 @@ static int __init armada_370_xp_timer_common_init(struct device_node *np)
|
|||||||
"armada_370_xp_clocksource",
|
"armada_370_xp_clocksource",
|
||||||
timer_clk, 300, 32, clocksource_mmio_readl_down);
|
timer_clk, 300, 32, clocksource_mmio_readl_down);
|
||||||
if (res) {
|
if (res) {
|
||||||
pr_err("Failed to initialize clocksource mmio");
|
pr_err("Failed to initialize clocksource mmio\n");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +315,7 @@ static int __init armada_370_xp_timer_common_init(struct device_node *np)
|
|||||||
armada_370_xp_evt);
|
armada_370_xp_evt);
|
||||||
/* Immediately configure the timer on the boot CPU */
|
/* Immediately configure the timer on the boot CPU */
|
||||||
if (res) {
|
if (res) {
|
||||||
pr_err("Failed to request percpu irq");
|
pr_err("Failed to request percpu irq\n");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,7 +324,7 @@ static int __init armada_370_xp_timer_common_init(struct device_node *np)
|
|||||||
armada_370_xp_timer_starting_cpu,
|
armada_370_xp_timer_starting_cpu,
|
||||||
armada_370_xp_timer_dying_cpu);
|
armada_370_xp_timer_dying_cpu);
|
||||||
if (res) {
|
if (res) {
|
||||||
pr_err("Failed to setup hotplug state and timer");
|
pr_err("Failed to setup hotplug state and timer\n");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +339,7 @@ static int __init armada_xp_timer_init(struct device_node *np)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
pr_err("Failed to get clock");
|
pr_err("Failed to get clock\n");
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,7 +375,7 @@ static int __init armada_375_timer_init(struct device_node *np)
|
|||||||
|
|
||||||
/* Must have at least a clock */
|
/* Must have at least a clock */
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
pr_err("Failed to get clock");
|
pr_err("Failed to get clock\n");
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +399,7 @@ static int __init armada_370_timer_init(struct device_node *np)
|
|||||||
|
|
||||||
clk = of_clk_get(np, 0);
|
clk = of_clk_get(np, 0);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
pr_err("Failed to get clock");
|
pr_err("Failed to get clock\n");
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ static int __init efm32_clockevent_init(struct device_node *np)
|
|||||||
|
|
||||||
ret = setup_irq(irq, &efm32_clock_event_irq);
|
ret = setup_irq(irq, &efm32_clock_event_irq);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed setup irq");
|
pr_err("Failed setup irq\n");
|
||||||
goto err_setup_irq;
|
goto err_setup_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/clockchips.h>
|
#include <linux/clockchips.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
@ -36,6 +37,21 @@
|
|||||||
|
|
||||||
static void __iomem *timer_base;
|
static void __iomem *timer_base;
|
||||||
|
|
||||||
|
static unsigned long notrace orion_read_timer(void)
|
||||||
|
{
|
||||||
|
return ~readl(timer_base + TIMER0_VAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct delay_timer orion_delay_timer = {
|
||||||
|
.read_current_timer = orion_read_timer,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void orion_delay_timer_init(unsigned long rate)
|
||||||
|
{
|
||||||
|
orion_delay_timer.freq = rate;
|
||||||
|
register_current_timer_delay(&orion_delay_timer);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free-running clocksource handling.
|
* Free-running clocksource handling.
|
||||||
*/
|
*/
|
||||||
@ -106,6 +122,7 @@ static struct irqaction orion_clkevt_irq = {
|
|||||||
|
|
||||||
static int __init orion_timer_init(struct device_node *np)
|
static int __init orion_timer_init(struct device_node *np)
|
||||||
{
|
{
|
||||||
|
unsigned long rate;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
int irq, ret;
|
int irq, ret;
|
||||||
|
|
||||||
@ -124,7 +141,7 @@ static int __init orion_timer_init(struct device_node *np)
|
|||||||
|
|
||||||
ret = clk_prepare_enable(clk);
|
ret = clk_prepare_enable(clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to prepare clock");
|
pr_err("Failed to prepare clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +152,8 @@ static int __init orion_timer_init(struct device_node *np)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rate = clk_get_rate(clk);
|
||||||
|
|
||||||
/* setup timer0 as free-running clocksource */
|
/* setup timer0 as free-running clocksource */
|
||||||
writel(~0, timer_base + TIMER0_VAL);
|
writel(~0, timer_base + TIMER0_VAL);
|
||||||
writel(~0, timer_base + TIMER0_RELOAD);
|
writel(~0, timer_base + TIMER0_RELOAD);
|
||||||
@ -142,15 +161,15 @@ static int __init orion_timer_init(struct device_node *np)
|
|||||||
TIMER0_RELOAD_EN | TIMER0_EN,
|
TIMER0_RELOAD_EN | TIMER0_EN,
|
||||||
TIMER0_RELOAD_EN | TIMER0_EN);
|
TIMER0_RELOAD_EN | TIMER0_EN);
|
||||||
|
|
||||||
ret = clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
|
ret = clocksource_mmio_init(timer_base + TIMER0_VAL,
|
||||||
clk_get_rate(clk), 300, 32,
|
"orion_clocksource", rate, 300, 32,
|
||||||
clocksource_mmio_readl_down);
|
clocksource_mmio_readl_down);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to initialize mmio timer");
|
pr_err("Failed to initialize mmio timer\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
sched_clock_register(orion_read_sched_clock, 32, clk_get_rate(clk));
|
sched_clock_register(orion_read_sched_clock, 32, rate);
|
||||||
|
|
||||||
/* setup timer1 as clockevent timer */
|
/* setup timer1 as clockevent timer */
|
||||||
ret = setup_irq(irq, &orion_clkevt_irq);
|
ret = setup_irq(irq, &orion_clkevt_irq);
|
||||||
@ -162,9 +181,12 @@ static int __init orion_timer_init(struct device_node *np)
|
|||||||
ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
|
ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
|
||||||
orion_clkevt.cpumask = cpumask_of(0);
|
orion_clkevt.cpumask = cpumask_of(0);
|
||||||
orion_clkevt.irq = irq;
|
orion_clkevt.irq = irq;
|
||||||
clockevents_config_and_register(&orion_clkevt, clk_get_rate(clk),
|
clockevents_config_and_register(&orion_clkevt, rate,
|
||||||
ORION_ONESHOT_MIN, ORION_ONESHOT_MAX);
|
ORION_ONESHOT_MIN, ORION_ONESHOT_MAX);
|
||||||
|
|
||||||
|
|
||||||
|
orion_delay_timer_init(rate);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
|
CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
|
||||||
|
@ -192,7 +192,9 @@ static int sirfsoc_local_timer_starting_cpu(unsigned int cpu)
|
|||||||
ce->set_next_event = sirfsoc_timer_set_next_event;
|
ce->set_next_event = sirfsoc_timer_set_next_event;
|
||||||
clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60);
|
clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60);
|
||||||
ce->max_delta_ns = clockevent_delta2ns(-2, ce);
|
ce->max_delta_ns = clockevent_delta2ns(-2, ce);
|
||||||
|
ce->max_delta_ticks = (unsigned long)-2;
|
||||||
ce->min_delta_ns = clockevent_delta2ns(2, ce);
|
ce->min_delta_ns = clockevent_delta2ns(2, ce);
|
||||||
|
ce->min_delta_ticks = 2;
|
||||||
ce->cpumask = cpumask_of(cpu);
|
ce->cpumask = cpumask_of(cpu);
|
||||||
|
|
||||||
action->dev_id = ce;
|
action->dev_id = ce;
|
||||||
|
@ -226,7 +226,7 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node)
|
|||||||
|
|
||||||
ret = clocksource_register_hz(&data->clksrc, pit_rate);
|
ret = clocksource_register_hz(&data->clksrc, pit_rate);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to register clocksource");
|
pr_err("Failed to register clocksource\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,19 +161,19 @@ static int __init digicolor_timer_init(struct device_node *node)
|
|||||||
*/
|
*/
|
||||||
dc_timer_dev.base = of_iomap(node, 0);
|
dc_timer_dev.base = of_iomap(node, 0);
|
||||||
if (!dc_timer_dev.base) {
|
if (!dc_timer_dev.base) {
|
||||||
pr_err("Can't map registers");
|
pr_err("Can't map registers\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = irq_of_parse_and_map(node, dc_timer_dev.timer_id);
|
irq = irq_of_parse_and_map(node, dc_timer_dev.timer_id);
|
||||||
if (irq <= 0) {
|
if (irq <= 0) {
|
||||||
pr_err("Can't parse IRQ");
|
pr_err("Can't parse IRQ\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
clk = of_clk_get(node, 0);
|
clk = of_clk_get(node, 0);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
pr_err("Can't get timer clock");
|
pr_err("Can't get timer clock\n");
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
}
|
}
|
||||||
clk_prepare_enable(clk);
|
clk_prepare_enable(clk);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Gemini timer driver
|
* Faraday Technology FTTMR010 timer driver
|
||||||
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
|
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
|
||||||
*
|
*
|
||||||
* Based on a rewrite of arch/arm/mach-gemini/timer.c:
|
* Based on a rewrite of arch/arm/mach-gemini/timer.c:
|
||||||
@ -16,17 +16,7 @@
|
|||||||
#include <linux/clockchips.h>
|
#include <linux/clockchips.h>
|
||||||
#include <linux/clocksource.h>
|
#include <linux/clocksource.h>
|
||||||
#include <linux/sched_clock.h>
|
#include <linux/sched_clock.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
/*
|
|
||||||
* Relevant registers in the global syscon
|
|
||||||
*/
|
|
||||||
#define GLOBAL_STATUS 0x04
|
|
||||||
#define CPU_AHB_RATIO_MASK (0x3 << 18)
|
|
||||||
#define CPU_AHB_1_1 (0x0 << 18)
|
|
||||||
#define CPU_AHB_3_2 (0x1 << 18)
|
|
||||||
#define CPU_AHB_24_13 (0x2 << 18)
|
|
||||||
#define CPU_AHB_2_1 (0x3 << 18)
|
|
||||||
#define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register definitions for the timers
|
* Register definitions for the timers
|
||||||
@ -77,12 +67,12 @@
|
|||||||
static unsigned int tick_rate;
|
static unsigned int tick_rate;
|
||||||
static void __iomem *base;
|
static void __iomem *base;
|
||||||
|
|
||||||
static u64 notrace gemini_read_sched_clock(void)
|
static u64 notrace fttmr010_read_sched_clock(void)
|
||||||
{
|
{
|
||||||
return readl(base + TIMER3_COUNT);
|
return readl(base + TIMER3_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gemini_timer_set_next_event(unsigned long cycles,
|
static int fttmr010_timer_set_next_event(unsigned long cycles,
|
||||||
struct clock_event_device *evt)
|
struct clock_event_device *evt)
|
||||||
{
|
{
|
||||||
u32 cr;
|
u32 cr;
|
||||||
@ -96,7 +86,7 @@ static int gemini_timer_set_next_event(unsigned long cycles,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gemini_timer_shutdown(struct clock_event_device *evt)
|
static int fttmr010_timer_shutdown(struct clock_event_device *evt)
|
||||||
{
|
{
|
||||||
u32 cr;
|
u32 cr;
|
||||||
|
|
||||||
@ -127,7 +117,7 @@ static int gemini_timer_shutdown(struct clock_event_device *evt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gemini_timer_set_periodic(struct clock_event_device *evt)
|
static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
|
||||||
{
|
{
|
||||||
u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ);
|
u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ);
|
||||||
u32 cr;
|
u32 cr;
|
||||||
@ -158,54 +148,40 @@ static int gemini_timer_set_periodic(struct clock_event_device *evt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Use TIMER1 as clock event */
|
/* Use TIMER1 as clock event */
|
||||||
static struct clock_event_device gemini_clockevent = {
|
static struct clock_event_device fttmr010_clockevent = {
|
||||||
.name = "TIMER1",
|
.name = "TIMER1",
|
||||||
/* Reasonably fast and accurate clock event */
|
/* Reasonably fast and accurate clock event */
|
||||||
.rating = 300,
|
.rating = 300,
|
||||||
.shift = 32,
|
.shift = 32,
|
||||||
.features = CLOCK_EVT_FEAT_PERIODIC |
|
.features = CLOCK_EVT_FEAT_PERIODIC |
|
||||||
CLOCK_EVT_FEAT_ONESHOT,
|
CLOCK_EVT_FEAT_ONESHOT,
|
||||||
.set_next_event = gemini_timer_set_next_event,
|
.set_next_event = fttmr010_timer_set_next_event,
|
||||||
.set_state_shutdown = gemini_timer_shutdown,
|
.set_state_shutdown = fttmr010_timer_shutdown,
|
||||||
.set_state_periodic = gemini_timer_set_periodic,
|
.set_state_periodic = fttmr010_timer_set_periodic,
|
||||||
.set_state_oneshot = gemini_timer_shutdown,
|
.set_state_oneshot = fttmr010_timer_shutdown,
|
||||||
.tick_resume = gemini_timer_shutdown,
|
.tick_resume = fttmr010_timer_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IRQ handler for the timer
|
* IRQ handler for the timer
|
||||||
*/
|
*/
|
||||||
static irqreturn_t gemini_timer_interrupt(int irq, void *dev_id)
|
static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct clock_event_device *evt = &gemini_clockevent;
|
struct clock_event_device *evt = &fttmr010_clockevent;
|
||||||
|
|
||||||
evt->event_handler(evt);
|
evt->event_handler(evt);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irqaction gemini_timer_irq = {
|
static struct irqaction fttmr010_timer_irq = {
|
||||||
.name = "Gemini Timer Tick",
|
.name = "Faraday FTTMR010 Timer Tick",
|
||||||
.flags = IRQF_TIMER,
|
.flags = IRQF_TIMER,
|
||||||
.handler = gemini_timer_interrupt,
|
.handler = fttmr010_timer_interrupt,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init gemini_timer_of_init(struct device_node *np)
|
static int __init fttmr010_timer_common_init(struct device_node *np)
|
||||||
{
|
{
|
||||||
static struct regmap *map;
|
|
||||||
int irq;
|
int irq;
|
||||||
int ret;
|
|
||||||
u32 val;
|
|
||||||
|
|
||||||
map = syscon_regmap_lookup_by_phandle(np, "syscon");
|
|
||||||
if (IS_ERR(map)) {
|
|
||||||
pr_err("Can't get regmap for syscon handle");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
ret = regmap_read(map, GLOBAL_STATUS, &val);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("Can't read syscon status register");
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
base = of_iomap(np, 0);
|
base = of_iomap(np, 0);
|
||||||
if (!base) {
|
if (!base) {
|
||||||
@ -219,26 +195,6 @@ static int __init gemini_timer_of_init(struct device_node *np)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tick_rate = REG_TO_AHB_SPEED(val) * 1000000;
|
|
||||||
printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000);
|
|
||||||
|
|
||||||
tick_rate /= 6; /* APB bus run AHB*(1/6) */
|
|
||||||
|
|
||||||
switch (val & CPU_AHB_RATIO_MASK) {
|
|
||||||
case CPU_AHB_1_1:
|
|
||||||
printk(KERN_CONT "(1/1)\n");
|
|
||||||
break;
|
|
||||||
case CPU_AHB_3_2:
|
|
||||||
printk(KERN_CONT "(3/2)\n");
|
|
||||||
break;
|
|
||||||
case CPU_AHB_24_13:
|
|
||||||
printk(KERN_CONT "(24/13)\n");
|
|
||||||
break;
|
|
||||||
case CPU_AHB_2_1:
|
|
||||||
printk(KERN_CONT "(2/1)\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset the interrupt mask and status
|
* Reset the interrupt mask and status
|
||||||
*/
|
*/
|
||||||
@ -255,9 +211,9 @@ static int __init gemini_timer_of_init(struct device_node *np)
|
|||||||
writel(0, base + TIMER3_MATCH1);
|
writel(0, base + TIMER3_MATCH1);
|
||||||
writel(0, base + TIMER3_MATCH2);
|
writel(0, base + TIMER3_MATCH2);
|
||||||
clocksource_mmio_init(base + TIMER3_COUNT,
|
clocksource_mmio_init(base + TIMER3_COUNT,
|
||||||
"gemini_clocksource", tick_rate,
|
"fttmr010_clocksource", tick_rate,
|
||||||
300, 32, clocksource_mmio_readl_up);
|
300, 32, clocksource_mmio_readl_up);
|
||||||
sched_clock_register(gemini_read_sched_clock, 32, tick_rate);
|
sched_clock_register(fttmr010_read_sched_clock, 32, tick_rate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup clockevent timer (interrupt-driven.)
|
* Setup clockevent timer (interrupt-driven.)
|
||||||
@ -266,12 +222,82 @@ static int __init gemini_timer_of_init(struct device_node *np)
|
|||||||
writel(0, base + TIMER1_LOAD);
|
writel(0, base + TIMER1_LOAD);
|
||||||
writel(0, base + TIMER1_MATCH1);
|
writel(0, base + TIMER1_MATCH1);
|
||||||
writel(0, base + TIMER1_MATCH2);
|
writel(0, base + TIMER1_MATCH2);
|
||||||
setup_irq(irq, &gemini_timer_irq);
|
setup_irq(irq, &fttmr010_timer_irq);
|
||||||
gemini_clockevent.cpumask = cpumask_of(0);
|
fttmr010_clockevent.cpumask = cpumask_of(0);
|
||||||
clockevents_config_and_register(&gemini_clockevent, tick_rate,
|
clockevents_config_and_register(&fttmr010_clockevent, tick_rate,
|
||||||
1, 0xffffffff);
|
1, 0xffffffff);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
CLOCKSOURCE_OF_DECLARE(nomadik_mtu, "cortina,gemini-timer",
|
|
||||||
gemini_timer_of_init);
|
static int __init fttmr010_timer_of_init(struct device_node *np)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* These implementations require a clock reference.
|
||||||
|
* FIXME: we currently only support clocking using PCLK
|
||||||
|
* and using EXTCLK is not supported in the driver.
|
||||||
|
*/
|
||||||
|
struct clk *clk;
|
||||||
|
|
||||||
|
clk = of_clk_get_by_name(np, "PCLK");
|
||||||
|
if (IS_ERR(clk)) {
|
||||||
|
pr_err("could not get PCLK");
|
||||||
|
return PTR_ERR(clk);
|
||||||
|
}
|
||||||
|
tick_rate = clk_get_rate(clk);
|
||||||
|
|
||||||
|
return fttmr010_timer_common_init(np);
|
||||||
|
}
|
||||||
|
CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_of_init);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gemini-specific: relevant registers in the global syscon
|
||||||
|
*/
|
||||||
|
#define GLOBAL_STATUS 0x04
|
||||||
|
#define CPU_AHB_RATIO_MASK (0x3 << 18)
|
||||||
|
#define CPU_AHB_1_1 (0x0 << 18)
|
||||||
|
#define CPU_AHB_3_2 (0x1 << 18)
|
||||||
|
#define CPU_AHB_24_13 (0x2 << 18)
|
||||||
|
#define CPU_AHB_2_1 (0x3 << 18)
|
||||||
|
#define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130)
|
||||||
|
|
||||||
|
static int __init gemini_timer_of_init(struct device_node *np)
|
||||||
|
{
|
||||||
|
static struct regmap *map;
|
||||||
|
int ret;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
map = syscon_regmap_lookup_by_phandle(np, "syscon");
|
||||||
|
if (IS_ERR(map)) {
|
||||||
|
pr_err("Can't get regmap for syscon handle\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
ret = regmap_read(map, GLOBAL_STATUS, &val);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Can't read syscon status register\n");
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
tick_rate = REG_TO_AHB_SPEED(val) * 1000000;
|
||||||
|
pr_info("Bus: %dMHz ", tick_rate / 1000000);
|
||||||
|
|
||||||
|
tick_rate /= 6; /* APB bus run AHB*(1/6) */
|
||||||
|
|
||||||
|
switch (val & CPU_AHB_RATIO_MASK) {
|
||||||
|
case CPU_AHB_1_1:
|
||||||
|
pr_cont("(1/1)\n");
|
||||||
|
break;
|
||||||
|
case CPU_AHB_3_2:
|
||||||
|
pr_cont("(3/2)\n");
|
||||||
|
break;
|
||||||
|
case CPU_AHB_24_13:
|
||||||
|
pr_cont("(24/13)\n");
|
||||||
|
break;
|
||||||
|
case CPU_AHB_2_1:
|
||||||
|
pr_cont("(2/1)\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fttmr010_timer_common_init(np);
|
||||||
|
}
|
||||||
|
CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", gemini_timer_of_init);
|
@ -200,7 +200,7 @@ static int __init integrator_ap_timer_init_of(struct device_node *node)
|
|||||||
err = of_property_read_string(of_aliases,
|
err = of_property_read_string(of_aliases,
|
||||||
"arm,timer-primary", &path);
|
"arm,timer-primary", &path);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("Failed to read property");
|
pr_warn("Failed to read property\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +209,7 @@ static int __init integrator_ap_timer_init_of(struct device_node *node)
|
|||||||
err = of_property_read_string(of_aliases,
|
err = of_property_read_string(of_aliases,
|
||||||
"arm,timer-secondary", &path);
|
"arm,timer-secondary", &path);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("Failed to read property");
|
pr_warn("Failed to read property\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ static int __init nps_get_timer_clk(struct device_node *node,
|
|||||||
*clk = of_clk_get(node, 0);
|
*clk = of_clk_get(node, 0);
|
||||||
ret = PTR_ERR_OR_ZERO(*clk);
|
ret = PTR_ERR_OR_ZERO(*clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("timer missing clk");
|
pr_err("timer missing clk\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ static int __init nps_setup_clockevent(struct device_node *node)
|
|||||||
|
|
||||||
nps_timer0_irq = irq_of_parse_and_map(node, 0);
|
nps_timer0_irq = irq_of_parse_and_map(node, 0);
|
||||||
if (nps_timer0_irq <= 0) {
|
if (nps_timer0_irq <= 0) {
|
||||||
pr_err("clockevent: missing irq");
|
pr_err("clockevent: missing irq\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ static int __init nps_setup_clockevent(struct device_node *node)
|
|||||||
nps_timer_starting_cpu,
|
nps_timer_starting_cpu,
|
||||||
nps_timer_dying_cpu);
|
nps_timer_dying_cpu);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to setup hotplug state");
|
pr_err("Failed to setup hotplug state\n");
|
||||||
clk_disable_unprepare(clk);
|
clk_disable_unprepare(clk);
|
||||||
free_percpu_irq(nps_timer0_irq, &nps_clockevent_device);
|
free_percpu_irq(nps_timer0_irq, &nps_clockevent_device);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -196,20 +196,20 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np)
|
|||||||
|
|
||||||
clk = of_clk_get(np, 0);
|
clk = of_clk_get(np, 0);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
pr_err("Failed to get clock");
|
pr_err("Failed to get clock\n");
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_prepare_enable(clk);
|
ret = clk_prepare_enable(clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to enable clock");
|
pr_err("Failed to enable clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rate = clk_get_rate(clk);
|
rate = clk_get_rate(clk);
|
||||||
|
|
||||||
if (rate < PRIMA2_CLOCK_FREQ || rate % PRIMA2_CLOCK_FREQ) {
|
if (rate < PRIMA2_CLOCK_FREQ || rate % PRIMA2_CLOCK_FREQ) {
|
||||||
pr_err("Invalid clock rate");
|
pr_err("Invalid clock rate\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np)
|
|||||||
|
|
||||||
ret = clocksource_register_hz(&sirfsoc_clocksource, PRIMA2_CLOCK_FREQ);
|
ret = clocksource_register_hz(&sirfsoc_clocksource, PRIMA2_CLOCK_FREQ);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to register clocksource");
|
pr_err("Failed to register clocksource\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np)
|
|||||||
|
|
||||||
ret = setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
|
ret = setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Failed to setup irq");
|
pr_err("Failed to setup irq\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,13 +299,13 @@ static int __init integrator_cp_of_init(struct device_node *np)
|
|||||||
|
|
||||||
base = of_iomap(np, 0);
|
base = of_iomap(np, 0);
|
||||||
if (!base) {
|
if (!base) {
|
||||||
pr_err("Failed to iomap");
|
pr_err("Failed to iomap\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
clk = of_clk_get(np, 0);
|
clk = of_clk_get(np, 0);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
pr_err("Failed to get clock");
|
pr_err("Failed to get clock\n");
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,19 +332,19 @@ static int __init sun5i_timer_init(struct device_node *node)
|
|||||||
|
|
||||||
timer_base = of_io_request_and_map(node, 0, of_node_full_name(node));
|
timer_base = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||||
if (IS_ERR(timer_base)) {
|
if (IS_ERR(timer_base)) {
|
||||||
pr_err("Can't map registers");
|
pr_err("Can't map registers\n");
|
||||||
return PTR_ERR(timer_base);;
|
return PTR_ERR(timer_base);;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = irq_of_parse_and_map(node, 0);
|
irq = irq_of_parse_and_map(node, 0);
|
||||||
if (irq <= 0) {
|
if (irq <= 0) {
|
||||||
pr_err("Can't parse IRQ");
|
pr_err("Can't parse IRQ\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
clk = of_clk_get(node, 0);
|
clk = of_clk_get(node, 0);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
pr_err("Can't get timer clock");
|
pr_err("Can't get timer clock\n");
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ static int __init pit_timer_init(struct device_node *np)
|
|||||||
|
|
||||||
timer_base = of_iomap(np, 0);
|
timer_base = of_iomap(np, 0);
|
||||||
if (!timer_base) {
|
if (!timer_base) {
|
||||||
pr_err("Failed to iomap");
|
pr_err("Failed to iomap\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,30 +97,26 @@ static s32 scaled_ppm_to_ppb(long ppm)
|
|||||||
|
|
||||||
/* posix clock implementation */
|
/* posix clock implementation */
|
||||||
|
|
||||||
static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp)
|
static int ptp_clock_getres(struct posix_clock *pc, struct timespec64 *tp)
|
||||||
{
|
{
|
||||||
tp->tv_sec = 0;
|
tp->tv_sec = 0;
|
||||||
tp->tv_nsec = 1;
|
tp->tv_nsec = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp)
|
static int ptp_clock_settime(struct posix_clock *pc, const struct timespec64 *tp)
|
||||||
{
|
{
|
||||||
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
|
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
|
||||||
struct timespec64 ts = timespec_to_timespec64(*tp);
|
|
||||||
|
|
||||||
return ptp->info->settime64(ptp->info, &ts);
|
return ptp->info->settime64(ptp->info, tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ptp_clock_gettime(struct posix_clock *pc, struct timespec *tp)
|
static int ptp_clock_gettime(struct posix_clock *pc, struct timespec64 *tp)
|
||||||
{
|
{
|
||||||
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
|
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
|
||||||
struct timespec64 ts;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = ptp->info->gettime64(ptp->info, &ts);
|
err = ptp->info->gettime64(ptp->info, tp);
|
||||||
if (!err)
|
|
||||||
*tp = timespec64_to_timespec(ts);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +129,7 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx)
|
|||||||
ops = ptp->info;
|
ops = ptp->info;
|
||||||
|
|
||||||
if (tx->modes & ADJ_SETOFFSET) {
|
if (tx->modes & ADJ_SETOFFSET) {
|
||||||
struct timespec ts;
|
struct timespec64 ts;
|
||||||
ktime_t kt;
|
ktime_t kt;
|
||||||
s64 delta;
|
s64 delta;
|
||||||
|
|
||||||
@ -146,7 +142,7 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx)
|
|||||||
if ((unsigned long) ts.tv_nsec >= NSEC_PER_SEC)
|
if ((unsigned long) ts.tv_nsec >= NSEC_PER_SEC)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
kt = timespec_to_ktime(ts);
|
kt = timespec64_to_ktime(ts);
|
||||||
delta = ktime_to_ns(kt);
|
delta = ktime_to_ns(kt);
|
||||||
err = ops->adjtime(ops, delta);
|
err = ops->adjtime(ops, delta);
|
||||||
} else if (tx->modes & ADJ_FREQUENCY) {
|
} else if (tx->modes & ADJ_FREQUENCY) {
|
||||||
|
@ -16,9 +16,13 @@
|
|||||||
#ifndef __CLKSOURCE_ARM_ARCH_TIMER_H
|
#ifndef __CLKSOURCE_ARM_ARCH_TIMER_H
|
||||||
#define __CLKSOURCE_ARM_ARCH_TIMER_H
|
#define __CLKSOURCE_ARM_ARCH_TIMER_H
|
||||||
|
|
||||||
|
#include <linux/bitops.h>
|
||||||
#include <linux/timecounter.h>
|
#include <linux/timecounter.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#define ARCH_TIMER_TYPE_CP15 BIT(0)
|
||||||
|
#define ARCH_TIMER_TYPE_MEM BIT(1)
|
||||||
|
|
||||||
#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
|
#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
|
||||||
#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
|
#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
|
||||||
#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
|
#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
|
||||||
@ -34,11 +38,27 @@ enum arch_timer_reg {
|
|||||||
ARCH_TIMER_REG_TVAL,
|
ARCH_TIMER_REG_TVAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum arch_timer_ppi_nr {
|
||||||
|
ARCH_TIMER_PHYS_SECURE_PPI,
|
||||||
|
ARCH_TIMER_PHYS_NONSECURE_PPI,
|
||||||
|
ARCH_TIMER_VIRT_PPI,
|
||||||
|
ARCH_TIMER_HYP_PPI,
|
||||||
|
ARCH_TIMER_MAX_TIMER_PPI
|
||||||
|
};
|
||||||
|
|
||||||
|
enum arch_timer_spi_nr {
|
||||||
|
ARCH_TIMER_PHYS_SPI,
|
||||||
|
ARCH_TIMER_VIRT_SPI,
|
||||||
|
ARCH_TIMER_MAX_TIMER_SPI
|
||||||
|
};
|
||||||
|
|
||||||
#define ARCH_TIMER_PHYS_ACCESS 0
|
#define ARCH_TIMER_PHYS_ACCESS 0
|
||||||
#define ARCH_TIMER_VIRT_ACCESS 1
|
#define ARCH_TIMER_VIRT_ACCESS 1
|
||||||
#define ARCH_TIMER_MEM_PHYS_ACCESS 2
|
#define ARCH_TIMER_MEM_PHYS_ACCESS 2
|
||||||
#define ARCH_TIMER_MEM_VIRT_ACCESS 3
|
#define ARCH_TIMER_MEM_VIRT_ACCESS 3
|
||||||
|
|
||||||
|
#define ARCH_TIMER_MEM_MAX_FRAMES 8
|
||||||
|
|
||||||
#define ARCH_TIMER_USR_PCT_ACCESS_EN (1 << 0) /* physical counter */
|
#define ARCH_TIMER_USR_PCT_ACCESS_EN (1 << 0) /* physical counter */
|
||||||
#define ARCH_TIMER_USR_VCT_ACCESS_EN (1 << 1) /* virtual counter */
|
#define ARCH_TIMER_USR_VCT_ACCESS_EN (1 << 1) /* virtual counter */
|
||||||
#define ARCH_TIMER_VIRT_EVT_EN (1 << 2)
|
#define ARCH_TIMER_VIRT_EVT_EN (1 << 2)
|
||||||
@ -54,6 +74,20 @@ struct arch_timer_kvm_info {
|
|||||||
int virtual_irq;
|
int virtual_irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct arch_timer_mem_frame {
|
||||||
|
bool valid;
|
||||||
|
phys_addr_t cntbase;
|
||||||
|
size_t size;
|
||||||
|
int phys_irq;
|
||||||
|
int virt_irq;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct arch_timer_mem {
|
||||||
|
phys_addr_t cntctlbase;
|
||||||
|
size_t size;
|
||||||
|
struct arch_timer_mem_frame frame[ARCH_TIMER_MEM_MAX_FRAMES];
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ARM_ARCH_TIMER
|
#ifdef CONFIG_ARM_ARCH_TIMER
|
||||||
|
|
||||||
extern u32 arch_timer_get_rate(void);
|
extern u32 arch_timer_get_rate(void);
|
||||||
|
@ -591,6 +591,13 @@ enum acpi_reconfig_event {
|
|||||||
int acpi_reconfig_notifier_register(struct notifier_block *nb);
|
int acpi_reconfig_notifier_register(struct notifier_block *nb);
|
||||||
int acpi_reconfig_notifier_unregister(struct notifier_block *nb);
|
int acpi_reconfig_notifier_unregister(struct notifier_block *nb);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI_GTDT
|
||||||
|
int acpi_gtdt_init(struct acpi_table_header *table, int *platform_timer_count);
|
||||||
|
int acpi_gtdt_map_ppi(int type);
|
||||||
|
bool acpi_gtdt_c3stop(int type);
|
||||||
|
int acpi_arch_timer_mem_init(struct arch_timer_mem *timer_mem, int *timer_count);
|
||||||
|
#endif
|
||||||
|
|
||||||
#else /* !CONFIG_ACPI */
|
#else /* !CONFIG_ACPI */
|
||||||
|
|
||||||
#define acpi_disabled 1
|
#define acpi_disabled 1
|
||||||
|
@ -182,7 +182,6 @@ extern u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *e
|
|||||||
extern void clockevents_register_device(struct clock_event_device *dev);
|
extern void clockevents_register_device(struct clock_event_device *dev);
|
||||||
extern int clockevents_unbind_device(struct clock_event_device *ced, int cpu);
|
extern int clockevents_unbind_device(struct clock_event_device *ced, int cpu);
|
||||||
|
|
||||||
extern void clockevents_config(struct clock_event_device *dev, u32 freq);
|
|
||||||
extern void clockevents_config_and_register(struct clock_event_device *dev,
|
extern void clockevents_config_and_register(struct clock_event_device *dev,
|
||||||
u32 freq, unsigned long min_delta,
|
u32 freq, unsigned long min_delta,
|
||||||
unsigned long max_delta);
|
unsigned long max_delta);
|
||||||
|
@ -120,7 +120,7 @@ struct clocksource {
|
|||||||
#define CLOCK_SOURCE_RESELECT 0x100
|
#define CLOCK_SOURCE_RESELECT 0x100
|
||||||
|
|
||||||
/* simplify initialization of mask field */
|
/* simplify initialization of mask field */
|
||||||
#define CLOCKSOURCE_MASK(bits) (u64)((bits) < 64 ? ((1ULL<<(bits))-1) : -1)
|
#define CLOCKSOURCE_MASK(bits) GENMASK_ULL((bits) - 1, 0)
|
||||||
|
|
||||||
static inline u32 clocksource_freq2mult(u32 freq, u32 shift_constant, u64 from)
|
static inline u32 clocksource_freq2mult(u32 freq, u32 shift_constant, u64 from)
|
||||||
{
|
{
|
||||||
|
@ -276,8 +276,6 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer)
|
|||||||
return timer->base->cpu_base->hres_active;
|
return timer->base->cpu_base->hres_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void hrtimer_peek_ahead_timers(void);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The resolution of the clocks. The resolution value is returned in
|
* The resolution of the clocks. The resolution value is returned in
|
||||||
* the clock_getres() system call to give application programmers an
|
* the clock_getres() system call to give application programmers an
|
||||||
@ -300,8 +298,6 @@ extern unsigned int hrtimer_resolution;
|
|||||||
|
|
||||||
#define hrtimer_resolution (unsigned int)LOW_RES_NSEC
|
#define hrtimer_resolution (unsigned int)LOW_RES_NSEC
|
||||||
|
|
||||||
static inline void hrtimer_peek_ahead_timers(void) { }
|
|
||||||
|
|
||||||
static inline int hrtimer_is_hres_active(struct hrtimer *timer)
|
static inline int hrtimer_is_hres_active(struct hrtimer *timer)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@ -456,7 +452,7 @@ static inline u64 hrtimer_forward_now(struct hrtimer *timer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Precise sleep: */
|
/* Precise sleep: */
|
||||||
extern long hrtimer_nanosleep(struct timespec *rqtp,
|
extern long hrtimer_nanosleep(struct timespec64 *rqtp,
|
||||||
struct timespec __user *rmtp,
|
struct timespec __user *rmtp,
|
||||||
const enum hrtimer_mode mode,
|
const enum hrtimer_mode mode,
|
||||||
const clockid_t clockid);
|
const clockid_t clockid);
|
||||||
|
@ -258,7 +258,6 @@ extern unsigned int gic_present;
|
|||||||
extern void gic_init(unsigned long gic_base_addr,
|
extern void gic_init(unsigned long gic_base_addr,
|
||||||
unsigned long gic_addrspace_size, unsigned int cpu_vec,
|
unsigned long gic_addrspace_size, unsigned int cpu_vec,
|
||||||
unsigned int irqbase);
|
unsigned int irqbase);
|
||||||
extern void gic_clocksource_init(unsigned int);
|
|
||||||
extern u64 gic_read_count(void);
|
extern u64 gic_read_count(void);
|
||||||
extern unsigned int gic_get_count_width(void);
|
extern unsigned int gic_get_count_width(void);
|
||||||
extern u64 gic_read_compare(void);
|
extern u64 gic_read_compare(void);
|
||||||
|
@ -59,23 +59,23 @@ struct posix_clock_operations {
|
|||||||
|
|
||||||
int (*clock_adjtime)(struct posix_clock *pc, struct timex *tx);
|
int (*clock_adjtime)(struct posix_clock *pc, struct timex *tx);
|
||||||
|
|
||||||
int (*clock_gettime)(struct posix_clock *pc, struct timespec *ts);
|
int (*clock_gettime)(struct posix_clock *pc, struct timespec64 *ts);
|
||||||
|
|
||||||
int (*clock_getres) (struct posix_clock *pc, struct timespec *ts);
|
int (*clock_getres) (struct posix_clock *pc, struct timespec64 *ts);
|
||||||
|
|
||||||
int (*clock_settime)(struct posix_clock *pc,
|
int (*clock_settime)(struct posix_clock *pc,
|
||||||
const struct timespec *ts);
|
const struct timespec64 *ts);
|
||||||
|
|
||||||
int (*timer_create) (struct posix_clock *pc, struct k_itimer *kit);
|
int (*timer_create) (struct posix_clock *pc, struct k_itimer *kit);
|
||||||
|
|
||||||
int (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit);
|
int (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit);
|
||||||
|
|
||||||
void (*timer_gettime)(struct posix_clock *pc,
|
void (*timer_gettime)(struct posix_clock *pc,
|
||||||
struct k_itimer *kit, struct itimerspec *tsp);
|
struct k_itimer *kit, struct itimerspec64 *tsp);
|
||||||
|
|
||||||
int (*timer_settime)(struct posix_clock *pc,
|
int (*timer_settime)(struct posix_clock *pc,
|
||||||
struct k_itimer *kit, int flags,
|
struct k_itimer *kit, int flags,
|
||||||
struct itimerspec *tsp, struct itimerspec *old);
|
struct itimerspec64 *tsp, struct itimerspec64 *old);
|
||||||
/*
|
/*
|
||||||
* Optional character device methods:
|
* Optional character device methods:
|
||||||
*/
|
*/
|
||||||
|
@ -87,22 +87,22 @@ struct k_itimer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct k_clock {
|
struct k_clock {
|
||||||
int (*clock_getres) (const clockid_t which_clock, struct timespec *tp);
|
int (*clock_getres) (const clockid_t which_clock, struct timespec64 *tp);
|
||||||
int (*clock_set) (const clockid_t which_clock,
|
int (*clock_set) (const clockid_t which_clock,
|
||||||
const struct timespec *tp);
|
const struct timespec64 *tp);
|
||||||
int (*clock_get) (const clockid_t which_clock, struct timespec * tp);
|
int (*clock_get) (const clockid_t which_clock, struct timespec64 *tp);
|
||||||
int (*clock_adj) (const clockid_t which_clock, struct timex *tx);
|
int (*clock_adj) (const clockid_t which_clock, struct timex *tx);
|
||||||
int (*timer_create) (struct k_itimer *timer);
|
int (*timer_create) (struct k_itimer *timer);
|
||||||
int (*nsleep) (const clockid_t which_clock, int flags,
|
int (*nsleep) (const clockid_t which_clock, int flags,
|
||||||
struct timespec *, struct timespec __user *);
|
struct timespec64 *, struct timespec __user *);
|
||||||
long (*nsleep_restart) (struct restart_block *restart_block);
|
long (*nsleep_restart) (struct restart_block *restart_block);
|
||||||
int (*timer_set) (struct k_itimer * timr, int flags,
|
int (*timer_set) (struct k_itimer *timr, int flags,
|
||||||
struct itimerspec * new_setting,
|
struct itimerspec64 *new_setting,
|
||||||
struct itimerspec * old_setting);
|
struct itimerspec64 *old_setting);
|
||||||
int (*timer_del) (struct k_itimer * timr);
|
int (*timer_del) (struct k_itimer *timr);
|
||||||
#define TIMER_RETRY 1
|
#define TIMER_RETRY 1
|
||||||
void (*timer_get) (struct k_itimer * timr,
|
void (*timer_get) (struct k_itimer *timr,
|
||||||
struct itimerspec * cur_setting);
|
struct itimerspec64 *cur_setting);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct k_clock clock_posix_cpu;
|
extern struct k_clock clock_posix_cpu;
|
||||||
|
@ -19,21 +19,6 @@ extern void do_gettimeofday(struct timeval *tv);
|
|||||||
extern int do_settimeofday64(const struct timespec64 *ts);
|
extern int do_settimeofday64(const struct timespec64 *ts);
|
||||||
extern int do_sys_settimeofday64(const struct timespec64 *tv,
|
extern int do_sys_settimeofday64(const struct timespec64 *tv,
|
||||||
const struct timezone *tz);
|
const struct timezone *tz);
|
||||||
static inline int do_sys_settimeofday(const struct timespec *tv,
|
|
||||||
const struct timezone *tz)
|
|
||||||
{
|
|
||||||
struct timespec64 ts64;
|
|
||||||
|
|
||||||
if (!tv)
|
|
||||||
return do_sys_settimeofday64(NULL, tz);
|
|
||||||
|
|
||||||
if (!timespec_valid(tv))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
ts64 = timespec_to_timespec64(*tv);
|
|
||||||
return do_sys_settimeofday64(&ts64, tz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kernel time accessors
|
* Kernel time accessors
|
||||||
*/
|
*/
|
||||||
@ -273,6 +258,11 @@ static inline void timekeeping_clocktai(struct timespec *ts)
|
|||||||
*ts = ktime_to_timespec(ktime_get_clocktai());
|
*ts = ktime_to_timespec(ktime_get_clocktai());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void timekeeping_clocktai64(struct timespec64 *ts)
|
||||||
|
{
|
||||||
|
*ts = ktime_to_timespec64(ktime_get_clocktai());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RTC specific
|
* RTC specific
|
||||||
*/
|
*/
|
||||||
|
@ -108,8 +108,8 @@ COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv,
|
|||||||
COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv,
|
COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv,
|
||||||
struct timezone __user *, tz)
|
struct timezone __user *, tz)
|
||||||
{
|
{
|
||||||
|
struct timespec64 new_ts;
|
||||||
struct timeval user_tv;
|
struct timeval user_tv;
|
||||||
struct timespec new_ts;
|
|
||||||
struct timezone new_tz;
|
struct timezone new_tz;
|
||||||
|
|
||||||
if (tv) {
|
if (tv) {
|
||||||
@ -123,7 +123,7 @@ COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv,
|
|||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
|
return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __compat_get_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
|
static int __compat_get_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
|
||||||
@ -240,18 +240,20 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
|
|||||||
struct compat_timespec __user *, rmtp)
|
struct compat_timespec __user *, rmtp)
|
||||||
{
|
{
|
||||||
struct timespec tu, rmt;
|
struct timespec tu, rmt;
|
||||||
|
struct timespec64 tu64;
|
||||||
mm_segment_t oldfs;
|
mm_segment_t oldfs;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
if (compat_get_timespec(&tu, rqtp))
|
if (compat_get_timespec(&tu, rqtp))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (!timespec_valid(&tu))
|
tu64 = timespec_to_timespec64(tu);
|
||||||
|
if (!timespec64_valid(&tu64))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
oldfs = get_fs();
|
oldfs = get_fs();
|
||||||
set_fs(KERNEL_DS);
|
set_fs(KERNEL_DS);
|
||||||
ret = hrtimer_nanosleep(&tu,
|
ret = hrtimer_nanosleep(&tu64,
|
||||||
rmtp ? (struct timespec __user *)&rmt : NULL,
|
rmtp ? (struct timespec __user *)&rmt : NULL,
|
||||||
HRTIMER_MODE_REL, CLOCK_MONOTONIC);
|
HRTIMER_MODE_REL, CLOCK_MONOTONIC);
|
||||||
set_fs(oldfs);
|
set_fs(oldfs);
|
||||||
|
@ -1176,6 +1176,8 @@ static struct ctl_table kern_table[] = {
|
|||||||
.maxlen = sizeof(unsigned int),
|
.maxlen = sizeof(unsigned int),
|
||||||
.mode = 0644,
|
.mode = 0644,
|
||||||
.proc_handler = timer_migration_handler,
|
.proc_handler = timer_migration_handler,
|
||||||
|
.extra1 = &zero,
|
||||||
|
.extra2 = &one,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_BPF_SYSCALL
|
#ifdef CONFIG_BPF_SYSCALL
|
||||||
|
@ -541,7 +541,7 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
|
|||||||
*
|
*
|
||||||
* Returns the granularity of underlying alarm base clock
|
* Returns the granularity of underlying alarm base clock
|
||||||
*/
|
*/
|
||||||
static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp)
|
static int alarm_clock_getres(const clockid_t which_clock, struct timespec64 *tp)
|
||||||
{
|
{
|
||||||
if (!alarmtimer_get_rtcdev())
|
if (!alarmtimer_get_rtcdev())
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -558,14 +558,14 @@ static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp)
|
|||||||
*
|
*
|
||||||
* Provides the underlying alarm base time.
|
* Provides the underlying alarm base time.
|
||||||
*/
|
*/
|
||||||
static int alarm_clock_get(clockid_t which_clock, struct timespec *tp)
|
static int alarm_clock_get(clockid_t which_clock, struct timespec64 *tp)
|
||||||
{
|
{
|
||||||
struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)];
|
struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)];
|
||||||
|
|
||||||
if (!alarmtimer_get_rtcdev())
|
if (!alarmtimer_get_rtcdev())
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
*tp = ktime_to_timespec(base->gettime());
|
*tp = ktime_to_timespec64(base->gettime());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,19 +598,19 @@ static int alarm_timer_create(struct k_itimer *new_timer)
|
|||||||
* Copies out the current itimerspec data
|
* Copies out the current itimerspec data
|
||||||
*/
|
*/
|
||||||
static void alarm_timer_get(struct k_itimer *timr,
|
static void alarm_timer_get(struct k_itimer *timr,
|
||||||
struct itimerspec *cur_setting)
|
struct itimerspec64 *cur_setting)
|
||||||
{
|
{
|
||||||
ktime_t relative_expiry_time =
|
ktime_t relative_expiry_time =
|
||||||
alarm_expires_remaining(&(timr->it.alarm.alarmtimer));
|
alarm_expires_remaining(&(timr->it.alarm.alarmtimer));
|
||||||
|
|
||||||
if (ktime_to_ns(relative_expiry_time) > 0) {
|
if (ktime_to_ns(relative_expiry_time) > 0) {
|
||||||
cur_setting->it_value = ktime_to_timespec(relative_expiry_time);
|
cur_setting->it_value = ktime_to_timespec64(relative_expiry_time);
|
||||||
} else {
|
} else {
|
||||||
cur_setting->it_value.tv_sec = 0;
|
cur_setting->it_value.tv_sec = 0;
|
||||||
cur_setting->it_value.tv_nsec = 0;
|
cur_setting->it_value.tv_nsec = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_setting->it_interval = ktime_to_timespec(timr->it.alarm.interval);
|
cur_setting->it_interval = ktime_to_timespec64(timr->it.alarm.interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -640,8 +640,8 @@ static int alarm_timer_del(struct k_itimer *timr)
|
|||||||
* Sets the timer to new_setting, and starts the timer.
|
* Sets the timer to new_setting, and starts the timer.
|
||||||
*/
|
*/
|
||||||
static int alarm_timer_set(struct k_itimer *timr, int flags,
|
static int alarm_timer_set(struct k_itimer *timr, int flags,
|
||||||
struct itimerspec *new_setting,
|
struct itimerspec64 *new_setting,
|
||||||
struct itimerspec *old_setting)
|
struct itimerspec64 *old_setting)
|
||||||
{
|
{
|
||||||
ktime_t exp;
|
ktime_t exp;
|
||||||
|
|
||||||
@ -659,8 +659,8 @@ static int alarm_timer_set(struct k_itimer *timr, int flags,
|
|||||||
return TIMER_RETRY;
|
return TIMER_RETRY;
|
||||||
|
|
||||||
/* start the timer */
|
/* start the timer */
|
||||||
timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval);
|
timr->it.alarm.interval = timespec64_to_ktime(new_setting->it_interval);
|
||||||
exp = timespec_to_ktime(new_setting->it_value);
|
exp = timespec64_to_ktime(new_setting->it_value);
|
||||||
/* Convert (if necessary) to absolute time */
|
/* Convert (if necessary) to absolute time */
|
||||||
if (flags != TIMER_ABSTIME) {
|
if (flags != TIMER_ABSTIME) {
|
||||||
ktime_t now;
|
ktime_t now;
|
||||||
@ -790,13 +790,14 @@ out:
|
|||||||
* Handles clock_nanosleep calls against _ALARM clockids
|
* Handles clock_nanosleep calls against _ALARM clockids
|
||||||
*/
|
*/
|
||||||
static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
|
static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
|
||||||
struct timespec *tsreq, struct timespec __user *rmtp)
|
struct timespec64 *tsreq,
|
||||||
|
struct timespec __user *rmtp)
|
||||||
{
|
{
|
||||||
enum alarmtimer_type type = clock2alarm(which_clock);
|
enum alarmtimer_type type = clock2alarm(which_clock);
|
||||||
|
struct restart_block *restart;
|
||||||
struct alarm alarm;
|
struct alarm alarm;
|
||||||
ktime_t exp;
|
ktime_t exp;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct restart_block *restart;
|
|
||||||
|
|
||||||
if (!alarmtimer_get_rtcdev())
|
if (!alarmtimer_get_rtcdev())
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
@ -809,7 +810,7 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
|
|||||||
|
|
||||||
alarm_init(&alarm, type, alarmtimer_nsleep_wakeup);
|
alarm_init(&alarm, type, alarmtimer_nsleep_wakeup);
|
||||||
|
|
||||||
exp = timespec_to_ktime(*tsreq);
|
exp = timespec64_to_ktime(*tsreq);
|
||||||
/* Convert (if necessary) to absolute time */
|
/* Convert (if necessary) to absolute time */
|
||||||
if (flags != TIMER_ABSTIME) {
|
if (flags != TIMER_ABSTIME) {
|
||||||
ktime_t now = alarm_bases[type].gettime();
|
ktime_t now = alarm_bases[type].gettime();
|
||||||
|
@ -468,7 +468,7 @@ void clockevents_register_device(struct clock_event_device *dev)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(clockevents_register_device);
|
EXPORT_SYMBOL_GPL(clockevents_register_device);
|
||||||
|
|
||||||
void clockevents_config(struct clock_event_device *dev, u32 freq)
|
static void clockevents_config(struct clock_event_device *dev, u32 freq)
|
||||||
{
|
{
|
||||||
u64 sec;
|
u64 sec;
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user