Port corresponding Linux kernel driver. Currently VFxxx SoC is the intended consumer because it doesn't include common i.MX GPT block used as clocksource by other i.MX SoCs. Signed-off-by: Andrey Smirnov <andrew.smirnov@xxxxxxxxx> --- drivers/clocksource/Kconfig | 4 + drivers/clocksource/Makefile | 1 + drivers/clocksource/arm_global_timer.c | 113 +++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 drivers/clocksource/arm_global_timer.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 3d63f7ff1..2be5a76b3 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -70,3 +70,7 @@ config CLOCKSOURCE_ARMV8_TIMER bool default y depends on ARM && CPU_64v8 + +config CLOCKSOURCE_ARM_GLOBAL_TIMER + def_bool y + depends on ARM diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index ea33fff50..51f6cb2f4 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_CLOCKSOURCE_UEMD) += uemd.o obj-$(CONFIG_CLOCKSOURCE_ROCKCHIP)+= rk_timer.o obj-$(CONFIG_CLOCKSOURCE_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_CLOCKSOURCE_ARMV8_TIMER) += armv8-timer.o +obj-$(CONFIG_CLOCKSOURCE_ARM_GLOBAL_TIMER) += arm_global_timer.o diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c new file mode 100644 index 000000000..44e3a3c76 --- /dev/null +++ b/drivers/clocksource/arm_global_timer.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Clocksource driver for generic Cortex A9 timer block + * + * Copyright (C) 2018 Zodiac Inflight Innovations + * Author: Andrey Smirnov <andrew.smirnov@xxxxxxxxx> + * + * based on corresponding driver from Linux kernel with the following + * copyright: + * + * drivers/clocksource/arm_global_timer.c + * + * Copyright (C) 2013 STMicroelectronics (R&D) Limited. + * Author: Stuart Menefy <stuart.menefy@xxxxxx> + * Author: Srinivas Kandagatla <srinivas.kandagatla@xxxxxx> + */ +#include <common.h> +#include <init.h> +#include <clock.h> +#include <linux/clk.h> +#include <io.h> +#include <asm/system.h> + +#define GT_COUNTER0 0x00 +#define GT_COUNTER1 0x04 + +#define GT_CONTROL 0x08 +#define GT_CONTROL_TIMER_ENABLE BIT(0) /* this bit is NOT banked */ + +static void __iomem *gt_base; + +/* + * To get the value from the Global Timer Counter register proceed as follows: + * 1. Read the upper 32-bit timer counter register + * 2. Read the lower 32-bit timer counter register + * 3. Read the upper 32-bit timer counter register again. If the value is + * different to the 32-bit upper value read previously, go back to step 2. + * Otherwise the 64-bit timer counter value is correct. + */ +static uint64_t arm_global_clocksource_read(void) +{ + uint64_t counter; + uint32_t lower; + uint32_t upper, old_upper; + + upper = readl(gt_base + GT_COUNTER1); + do { + old_upper = upper; + lower = readl(gt_base + GT_COUNTER0); + upper = readl(gt_base + GT_COUNTER1); + } while (upper != old_upper); + + counter = upper; + counter <<= 32; + counter |= lower; + return counter; +} + +static struct clocksource cs = { + .read = arm_global_clocksource_read, + .mask = CLOCKSOURCE_MASK(64), + .shift = 0, +}; + +static int arm_global_timer_probe(struct device_d *dev) +{ + struct resource *iores; + struct clk *clk; + int ret; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + + clk = clk_get(dev, NULL); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(dev, "clock not found: %d\n", ret); + return ret; + } + + ret = clk_enable(clk); + if (ret) { + dev_err(dev, "clock failed to enable: %d\n", ret); + return ret; + } + + gt_base = IOMEM(iores->start); + + cs.mult = clocksource_hz2mult(clk_get_rate(clk), cs.shift); + + writel(0, gt_base + GT_CONTROL); + writel(0, gt_base + GT_COUNTER0); + writel(0, gt_base + GT_COUNTER1); + /* enables timer on all the cores */ + writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL); + + return init_clock(&cs); +} + +static struct of_device_id arm_global_timer_dt_ids[] = { + { .compatible = "arm,cortex-a9-global-timer", }, + { } +}; + +static struct driver_d arm_global_timer_driver = { + .name = "arm-global-timer", + .probe = arm_global_timer_probe, + .of_compatible = DRV_OF_COMPAT(arm_global_timer_dt_ids), +}; +postcore_platform_driver(arm_global_timer_driver); + -- 2.17.1 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox