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
13/*
14 * Implementation of a logical timer for NVIDIA platforms.
15 * NVIDIA has their own local timer implementations,
16 * that vary slightly from platform to platform.  TK1 and TX1 are similar;
17 * TX2 spreads them out over multiple 64k blocks.  TX2 also requires specific
18 * interrupt routing from the NVidia timer to the shared interrupt controller.
19 * Refer to the respective reference manual for more specific platform differences.
20 */
21#include <stdbool.h>
22#include <platsupport/timer.h>
23#include <platsupport/ltimer.h>
24#include <platsupport/plat/timer.h>
25#include <utils/util.h>
26
27#include "../../ltimer.h"
28
29typedef struct {
30    bool started;
31    nv_tmr_t nv_tmr;
32    ps_io_ops_t ops;
33} nv_tmr_ltimer_t;
34
35static int get_time(void *data, uint64_t *time)
36{
37    assert(data != NULL);
38    assert(time != NULL);
39
40    nv_tmr_ltimer_t *nv_tmr_ltimer = data;
41    *time = nv_tmr_get_time(&nv_tmr_ltimer->nv_tmr);
42    return 0;
43}
44
45static int get_resolution(void *data, uint64_t *resolution)
46{
47    return ENOSYS;
48}
49
50static int set_timeout(void *data, uint64_t ns, timeout_type_t type)
51{
52    assert(data != NULL);
53    nv_tmr_ltimer_t *nv_tmr_ltimer = data;
54
55    switch (type) {
56    case TIMEOUT_ABSOLUTE: {
57        uint64_t time = nv_tmr_get_time(&nv_tmr_ltimer->nv_tmr);
58        if (time >= ns) {
59            return ETIME;
60        }
61        return nv_tmr_set_timeout(&nv_tmr_ltimer->nv_tmr, false, ns - time);
62    }
63    case TIMEOUT_PERIODIC:
64    case TIMEOUT_RELATIVE:
65        return nv_tmr_set_timeout(&nv_tmr_ltimer->nv_tmr, (type == TIMEOUT_PERIODIC), ns);
66    }
67
68    return EINVAL;
69}
70
71static int reset(void *data)
72{
73    assert(data != NULL);
74    nv_tmr_ltimer_t *nv_tmr_ltimer = data;
75    nv_tmr_start(&nv_tmr_ltimer->nv_tmr);
76    nv_tmr_stop(&nv_tmr_ltimer->nv_tmr);
77    return 0;
78}
79
80static void destroy(void *data)
81{
82    assert(data);
83    nv_tmr_ltimer_t *nv_tmr_ltimer = data;
84    if (nv_tmr_ltimer->started) {
85        nv_tmr_stop(&nv_tmr_ltimer->nv_tmr);
86        nv_tmr_destroy(&nv_tmr_ltimer->nv_tmr);
87    }
88    ps_free(&nv_tmr_ltimer->ops.malloc_ops, sizeof(nv_tmr_ltimer), nv_tmr_ltimer);
89}
90
91int ltimer_default_init(ltimer_t *ltimer, ps_io_ops_t ops, ltimer_callback_fn_t callback, void *callback_token)
92{
93    if (!ltimer) {
94        return EINVAL;
95    }
96
97    ltimer->get_time = get_time;
98    ltimer->get_resolution = get_resolution;
99    ltimer->set_timeout = set_timeout;
100    ltimer->reset = reset;
101    ltimer->destroy = destroy;
102
103    int error = ps_calloc(&ops.malloc_ops, 1, sizeof(nv_tmr_ltimer_t), &ltimer->data);
104    if (error) {
105        return error;
106    }
107    assert(ltimer->data != NULL);
108    nv_tmr_ltimer_t *nv_tmr_ltimer = ltimer->data;
109    nv_tmr_ltimer->ops = ops;
110
111    error = nv_tmr_init(&nv_tmr_ltimer->nv_tmr, ops, NV_TMR_PATH, callback, callback_token);
112    if (error) {
113        destroy(ltimer->data);
114        return error;
115    }
116
117    nv_tmr_start(&nv_tmr_ltimer->nv_tmr);
118    nv_tmr_ltimer->started = true;
119    /* success! */
120    return 0;
121}
122
123/* This function is intended to be deleted,
124 * this is just left here for now so that stuff can compile */
125int ltimer_default_describe(ltimer_t *ltimer, ps_io_ops_t ops)
126{
127    ZF_LOGE("get_(nth/num)_(irqs/pmems) are not valid");
128    return EINVAL;
129}
130