diff options
Diffstat (limited to 'arch/m68k/atari')
-rw-r--r-- | arch/m68k/atari/Makefile | 1 | ||||
-rw-r--r-- | arch/m68k/atari/ataints.c | 4 | ||||
-rw-r--r-- | arch/m68k/atari/config.c | 2 | ||||
-rw-r--r-- | arch/m68k/atari/time.c | 70 |
4 files changed, 54 insertions, 23 deletions
diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile index 0b86bb6cfa87..2e3607f97253 100644 --- a/arch/m68k/atari/Makefile +++ b/arch/m68k/atari/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Makefile for Linux arch/m68k/atari source directory # diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index 3d2b63bedf05..56f02ea2c248 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -142,7 +142,7 @@ struct mfptimerbase { .name = "MFP Timer D" }; -static irqreturn_t mfptimer_handler(int irq, void *dev_id) +static irqreturn_t mfp_timer_d_handler(int irq, void *dev_id) { struct mfptimerbase *base = dev_id; int mach_irq; @@ -344,7 +344,7 @@ void __init atari_init_IRQ(void) st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6; /* request timer D dispatch handler */ - if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED, + if (request_irq(IRQ_MFP_TIMD, mfp_timer_d_handler, IRQF_SHARED, stmfp_base.name, &stmfp_base)) pr_err("Couldn't register %s interrupt\n", stmfp_base.name); diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index 4fcc4b1df1c0..902255e7b5b2 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -78,7 +78,6 @@ static void atari_heartbeat(int on); /* atari specific timer functions (in time.c) */ extern void atari_sched_init(irq_handler_t); -extern u32 atari_gettimeoffset(void); extern int atari_mste_hwclk (int, struct rtc_time *); extern int atari_tt_hwclk (int, struct rtc_time *); @@ -205,7 +204,6 @@ void __init config_atari(void) mach_init_IRQ = atari_init_IRQ; mach_get_model = atari_get_model; mach_get_hardware_list = atari_get_hardware_list; - arch_gettimeoffset = atari_gettimeoffset; mach_reset = atari_reset; mach_max_dma_address = 0xffffff; #if IS_ENABLED(CONFIG_INPUT_M68K_BEEP) diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c index 9cca64286464..ce923a523695 100644 --- a/arch/m68k/atari/time.c +++ b/arch/m68k/atari/time.c @@ -16,6 +16,7 @@ #include <linux/init.h> #include <linux/rtc.h> #include <linux/bcd.h> +#include <linux/clocksource.h> #include <linux/delay.h> #include <linux/export.h> @@ -24,6 +25,35 @@ DEFINE_SPINLOCK(rtc_lock); EXPORT_SYMBOL_GPL(rtc_lock); +static u64 atari_read_clk(struct clocksource *cs); + +static struct clocksource atari_clk = { + .name = "mfp", + .rating = 100, + .read = atari_read_clk, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static u32 clk_total; +static u8 last_timer_count; + +static irqreturn_t mfp_timer_c_handler(int irq, void *dev_id) +{ + irq_handler_t timer_routine = dev_id; + unsigned long flags; + + local_irq_save(flags); + do { + last_timer_count = st_mfp.tim_dt_c; + } while (last_timer_count == 1); + clk_total += INT_TICKS; + timer_routine(0, NULL); + local_irq_restore(flags); + + return IRQ_HANDLED; +} + void __init atari_sched_init(irq_handler_t timer_routine) { @@ -32,31 +62,33 @@ atari_sched_init(irq_handler_t timer_routine) /* start timer C, div = 1:100 */ st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60; /* install interrupt service routine for MFP Timer C */ - if (request_irq(IRQ_MFP_TIMC, timer_routine, 0, "timer", timer_routine)) + if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, IRQF_TIMER, "timer", + timer_routine)) pr_err("Couldn't register timer interrupt\n"); + + clocksource_register_hz(&atari_clk, INT_CLK); } /* ++andreas: gettimeoffset fixed to check for pending interrupt */ -#define TICK_SIZE 10000 - -/* This is always executed with interrupts disabled. */ -u32 atari_gettimeoffset(void) +static u64 atari_read_clk(struct clocksource *cs) { - u32 ticks, offset = 0; - - /* read MFP timer C current value */ - ticks = st_mfp.tim_dt_c; - /* The probability of underflow is less than 2% */ - if (ticks > INT_TICKS - INT_TICKS / 50) - /* Check for pending timer interrupt */ - if (st_mfp.int_pn_b & (1 << 5)) - offset = TICK_SIZE; - - ticks = INT_TICKS - ticks; - ticks = ticks * 10000L / INT_TICKS; - - return (ticks + offset) * 1000; + unsigned long flags; + u8 count; + u32 ticks; + + local_irq_save(flags); + /* Ensure that the count is monotonically decreasing, even though + * the result may briefly stop changing after counter wrap-around. + */ + count = min(st_mfp.tim_dt_c, last_timer_count); + last_timer_count = count; + + ticks = INT_TICKS - count; + ticks += clk_total; + local_irq_restore(flags); + + return ticks; } |