summaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/efi_x86.c
diff options
context:
space:
mode:
authorJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>2017-03-03 13:34:03 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2017-03-09 07:36:15 +0100
commitda11bd9d6028b811732e98bc8cbf3e00b7a1f2b3 (patch)
treeca93e81132d363be2e77e48de36ea0a026b010c4 /drivers/clocksource/efi_x86.c
parent8972eb7ff17ad058a6c6018305bb912138ab0ca2 (diff)
downloadbarebox-da11bd9d6028b811732e98bc8cbf3e00b7a1f2b3.tar.gz
barebox-da11bd9d6028b811732e98bc8cbf3e00b7a1f2b3.tar.xz
efi: move x86 clocksource to device/driver
so we can dynamicly register the device As we may need to use HW IP for clocksource. As on EFI we could use Timestamp GUID if present (Not often the case as it's not even enabled by default on any Target on EDK II not even OVMF) Or if we choose we could use a Simulated Timestamp driver that work on Event (Add Later) Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/clocksource/efi_x86.c')
-rw-r--r--drivers/clocksource/efi_x86.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/drivers/clocksource/efi_x86.c b/drivers/clocksource/efi_x86.c
new file mode 100644
index 0000000000..4d2657ea1d
--- /dev/null
+++ b/drivers/clocksource/efi_x86.c
@@ -0,0 +1,79 @@
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <efi.h>
+#include <efi/efi.h>
+#include <clock.h>
+
+#ifdef __x86_64__
+uint64_t ticks_read(void)
+{
+ uint64_t a, d;
+
+ __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
+
+ return (d << 32) | a;
+}
+#else
+uint64_t ticks_read(void)
+{
+ uint64_t val;
+
+ __asm__ volatile ("rdtsc" : "=A" (val));
+
+ return val;
+}
+#endif
+
+static uint64_t freq;
+
+/* count TSC ticks during a millisecond delay */
+static uint64_t ticks_freq(void)
+{
+ uint64_t ticks_start, ticks_end;
+
+ ticks_start = ticks_read();
+ BS->stall(1000);
+ ticks_end = ticks_read();
+
+ return (ticks_end - ticks_start) * 1000;
+}
+
+static uint64_t efi_x86_cs_read(void)
+{
+ return 1000 * 1000 * ticks_read() / freq;
+}
+
+static int efi_x86_cs_init(struct clocksource *cs)
+{
+ cs->mult = clocksource_hz2mult(1000 * 1000, cs->shift);
+
+ freq = ticks_freq();
+
+ return 0;
+}
+
+static struct clocksource efi_x86_cs = {
+ .read = efi_x86_cs_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .shift = 0,
+ .priority = 100,
+ .init = efi_x86_cs_init,
+};
+
+static int efi_x86_cs_probe(struct device_d *dev)
+{
+ return init_clock(&efi_x86_cs);
+}
+
+static struct driver_d efi_x86_cs_driver = {
+ .name = "efi-cs-x86",
+ .probe = efi_x86_cs_probe,
+};
+
+static int efi_x86_cs_initcall(void)
+{
+ return platform_driver_register(&efi_x86_cs_driver);
+}
+/* for efi the time must be init at core initcall level */
+core_initcall(efi_x86_cs_initcall);