1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12#pragma once
13
14#include <utils/attribute.h>
15#include <platsupport/plat/hpet.h>
16#include <platsupport/plat/pit.h>
17
18/* just read the tsc. This may be executed out of order as it is unserialised */
19static inline uint64_t
20rdtsc_pure(void)
21{
22    uint32_t high, low;
23
24    __asm__ __volatile__ (
25        "rdtsc"
26        : "=a" (low),
27        "=d" (high)
28        : /* no input */
29        : /* no clobbers */
30    );
31
32    return (((uint64_t) high) << 32llu) + (uint64_t) low;
33
34}
35
36/* serialised read of the tsc. This will execute in order and no memory loads will be executed
37 * beforehand */
38static inline uint64_t
39rdtsc_cpuid(void)
40{
41
42    uint32_t high, low;
43
44    __asm__ __volatile__ (
45        "movl $0, %%eax \n"
46        "movl $0, %%ecx \n"
47        "cpuid          \n"
48        "rdtsc          \n"
49        "movl %%edx, %0 \n"
50        "movl %%eax, %1 \n"
51        "movl $0, %%eax \n"
52        "movl $0, %%ecx \n"
53        "cpuid          \n"
54        : "=r" (high), "=r" (low)
55        : /* no inputs */
56        : "eax", "ebx", "ecx", "edx"
57    );
58
59    return ((uint64_t) high) << 32llu | (uint64_t) low;
60}
61
62#define TSC_TICKS_TO_NS(cycles_per_us) ((rdtsc_pure() / (uint64_t) cycles_per_us) * NS_IN_US)
63
64/**
65 * Calculates number of ticks per second of the time stamp counter
66 * This function takes complete control of the given timer for
67 * the duraction of the calculation and will reprogram it. It
68 * may also leave un-acked interrupts
69 *
70 * @return Ticks per second, or 0 on error
71 */
72uint64_t tsc_calculate_frequency_hpet(const hpet_t *hpet);
73uint64_t tsc_calculate_frequency_pit(pit_t *pit);
74
75static inline uint64_t tsc_get_time(uint64_t freq)
76{
77    return muldivu64(rdtsc_pure(), NS_IN_S, freq);
78}
79