diff options
Diffstat (limited to 'drivers/clocksource/meson6_timer.c')
-rw-r--r-- | drivers/clocksource/meson6_timer.c | 108 |
1 files changed, 64 insertions, 44 deletions
diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c index 92f20991a937..23c7638e2bb3 100644 --- a/drivers/clocksource/meson6_timer.c +++ b/drivers/clocksource/meson6_timer.c @@ -10,6 +10,8 @@ * warranty of any kind, whether express or implied. */ +#include <linux/bitfield.h> +#include <linux/bitops.h> #include <linux/clk.h> #include <linux/clockchips.h> #include <linux/interrupt.h> @@ -20,80 +22,96 @@ #include <linux/of_address.h> #include <linux/of_irq.h> -#define CED_ID 0 -#define CSD_ID 4 - -#define TIMER_ISA_MUX 0 -#define TIMER_ISA_VAL(t) (((t) + 1) << 2) - -#define TIMER_INPUT_BIT(t) (2 * (t)) -#define TIMER_ENABLE_BIT(t) (16 + (t)) -#define TIMER_PERIODIC_BIT(t) (12 + (t)) - -#define TIMER_CED_INPUT_MASK (3UL << TIMER_INPUT_BIT(CED_ID)) -#define TIMER_CSD_INPUT_MASK (7UL << TIMER_INPUT_BIT(CSD_ID)) - -#define TIMER_CED_UNIT_1US 0 -#define TIMER_CSD_UNIT_1US 1 +#define MESON_ISA_TIMER_MUX 0x00 +#define MESON_ISA_TIMER_MUX_TIMERD_EN BIT(19) +#define MESON_ISA_TIMER_MUX_TIMERC_EN BIT(18) +#define MESON_ISA_TIMER_MUX_TIMERB_EN BIT(17) +#define MESON_ISA_TIMER_MUX_TIMERA_EN BIT(16) +#define MESON_ISA_TIMER_MUX_TIMERD_MODE BIT(15) +#define MESON_ISA_TIMER_MUX_TIMERC_MODE BIT(14) +#define MESON_ISA_TIMER_MUX_TIMERB_MODE BIT(13) +#define MESON_ISA_TIMER_MUX_TIMERA_MODE BIT(12) +#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_MASK GENMASK(10, 8) +#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_SYSTEM_CLOCK 0x0 +#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_1US 0x1 +#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_10US 0x2 +#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_100US 0x3 +#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_1MS 0x4 +#define MESON_ISA_TIMER_MUX_TIMERD_INPUT_CLOCK_MASK GENMASK(7, 6) +#define MESON_ISA_TIMER_MUX_TIMERC_INPUT_CLOCK_MASK GENMASK(5, 4) +#define MESON_ISA_TIMER_MUX_TIMERB_INPUT_CLOCK_MASK GENMASK(3, 2) +#define MESON_ISA_TIMER_MUX_TIMERA_INPUT_CLOCK_MASK GENMASK(1, 0) +#define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_1US 0x0 +#define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_10US 0x1 +#define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_100US 0x0 +#define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_1MS 0x3 + +#define MESON_ISA_TIMERA 0x04 +#define MESON_ISA_TIMERB 0x08 +#define MESON_ISA_TIMERC 0x0c +#define MESON_ISA_TIMERD 0x10 +#define MESON_ISA_TIMERE 0x14 static void __iomem *timer_base; static u64 notrace meson6_timer_sched_read(void) { - return (u64)readl(timer_base + TIMER_ISA_VAL(CSD_ID)); + return (u64)readl(timer_base + MESON_ISA_TIMERE); } -static void meson6_clkevt_time_stop(unsigned char timer) +static void meson6_clkevt_time_stop(void) { - u32 val = readl(timer_base + TIMER_ISA_MUX); + u32 val = readl(timer_base + MESON_ISA_TIMER_MUX); - writel(val & ~TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); + writel(val & ~MESON_ISA_TIMER_MUX_TIMERA_EN, + timer_base + MESON_ISA_TIMER_MUX); } -static void meson6_clkevt_time_setup(unsigned char timer, unsigned long delay) +static void meson6_clkevt_time_setup(unsigned long delay) { - writel(delay, timer_base + TIMER_ISA_VAL(timer)); + writel(delay, timer_base + MESON_ISA_TIMERA); } -static void meson6_clkevt_time_start(unsigned char timer, bool periodic) +static void meson6_clkevt_time_start(bool periodic) { - u32 val = readl(timer_base + TIMER_ISA_MUX); + u32 val = readl(timer_base + MESON_ISA_TIMER_MUX); if (periodic) - val |= TIMER_PERIODIC_BIT(timer); + val |= MESON_ISA_TIMER_MUX_TIMERA_MODE; else - val &= ~TIMER_PERIODIC_BIT(timer); + val &= ~MESON_ISA_TIMER_MUX_TIMERA_MODE; - writel(val | TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); + writel(val | MESON_ISA_TIMER_MUX_TIMERA_EN, + timer_base + MESON_ISA_TIMER_MUX); } static int meson6_shutdown(struct clock_event_device *evt) { - meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_stop(); return 0; } static int meson6_set_oneshot(struct clock_event_device *evt) { - meson6_clkevt_time_stop(CED_ID); - meson6_clkevt_time_start(CED_ID, false); + meson6_clkevt_time_stop(); + meson6_clkevt_time_start(false); return 0; } static int meson6_set_periodic(struct clock_event_device *evt) { - meson6_clkevt_time_stop(CED_ID); - meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC / HZ - 1); - meson6_clkevt_time_start(CED_ID, true); + meson6_clkevt_time_stop(); + meson6_clkevt_time_setup(USEC_PER_SEC / HZ - 1); + meson6_clkevt_time_start(true); return 0; } static int meson6_clkevt_next_event(unsigned long evt, struct clock_event_device *unused) { - meson6_clkevt_time_stop(CED_ID); - meson6_clkevt_time_setup(CED_ID, evt); - meson6_clkevt_time_start(CED_ID, false); + meson6_clkevt_time_stop(); + meson6_clkevt_time_setup(evt); + meson6_clkevt_time_start(false); return 0; } @@ -144,22 +162,24 @@ static int __init meson6_timer_init(struct device_node *node) } /* Set 1us for timer E */ - val = readl(timer_base + TIMER_ISA_MUX); - val &= ~TIMER_CSD_INPUT_MASK; - val |= TIMER_CSD_UNIT_1US << TIMER_INPUT_BIT(CSD_ID); - writel(val, timer_base + TIMER_ISA_MUX); + val = readl(timer_base + MESON_ISA_TIMER_MUX); + val &= ~MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_MASK; + val |= FIELD_PREP(MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_MASK, + MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_1US); + writel(val, timer_base + MESON_ISA_TIMER_MUX); sched_clock_register(meson6_timer_sched_read, 32, USEC_PER_SEC); - clocksource_mmio_init(timer_base + TIMER_ISA_VAL(CSD_ID), node->name, + clocksource_mmio_init(timer_base + MESON_ISA_TIMERE, node->name, 1000 * 1000, 300, 32, clocksource_mmio_readl_up); /* Timer A base 1us */ - val &= ~TIMER_CED_INPUT_MASK; - val |= TIMER_CED_UNIT_1US << TIMER_INPUT_BIT(CED_ID); - writel(val, timer_base + TIMER_ISA_MUX); + val &= ~MESON_ISA_TIMER_MUX_TIMERA_INPUT_CLOCK_MASK; + val |= FIELD_PREP(MESON_ISA_TIMER_MUX_TIMERA_INPUT_CLOCK_MASK, + MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_1US); + writel(val, timer_base + MESON_ISA_TIMER_MUX); /* Stop the timer A */ - meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_stop(); ret = setup_irq(irq, &meson6_timer_irq); if (ret) { |