1/*
2 * Copyright 2019, 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/* Implementation of a logical timer for imx platforms
14 *
15 * Currently all imx platforms use some combination of GPT and EPIT timers to provide ltimer functionality. See platform specific timer.h for details.
16 */
17#include <platsupport/timer.h>
18#include <platsupport/ltimer.h>
19#include <platsupport/plat/timer.h>
20#include <platsupport/irq.h>
21
22#include <utils/util.h>
23
24#include "../../ltimer.h"
25
26typedef struct {
27    imx_timers_t timers;
28    bool timestamp_initialised;
29    bool timeout_initialised;
30    ps_io_ops_t ops;
31} imx_ltimer_t;
32
33static int get_time(void *data, uint64_t *time)
34{
35    assert(data != NULL);
36    assert(time != NULL);
37
38    imx_ltimer_t *imx_ltimer = data;
39    *time = imx_get_time(&imx_ltimer->timers);
40    return 0;
41}
42
43static int get_resolution(void *data, uint64_t *resolution)
44{
45    return ENOSYS;
46}
47
48static int set_timeout(void *data, uint64_t ns, timeout_type_t type)
49{
50    assert(data != NULL);
51    imx_ltimer_t *imx_ltimer = data;
52
53    if (type == TIMEOUT_ABSOLUTE) {
54        uint64_t current_time = imx_get_time(&imx_ltimer->timers);
55        ns -= current_time;
56    }
57
58    return imx_set_timeout(&imx_ltimer->timers, ns, type == TIMEOUT_PERIODIC);
59}
60
61static int reset(void *data)
62{
63    assert(data != NULL);
64    imx_ltimer_t *imx_ltimer = data;
65
66    /* reset the timers */
67    imx_stop_timeout(&imx_ltimer->timers);
68    imx_stop_timestamp(&imx_ltimer->timers);
69    imx_start_timestamp(&imx_ltimer->timers);
70
71    return 0;
72}
73
74static void destroy(void *data)
75{
76    assert(data);
77
78    imx_ltimer_t *imx_ltimer = data;
79
80    if (imx_ltimer->timestamp_initialised) {
81        imx_stop_timestamp(&imx_ltimer->timers);
82        ZF_LOGF_IF(imx_destroy_timestamp(&imx_ltimer->timers), "Failed to destroy the timestamp timer");
83    }
84
85    if (imx_ltimer->timeout_initialised) {
86        imx_stop_timeout(&imx_ltimer->timers);
87        ZF_LOGF_IF(imx_destroy_timeout(&imx_ltimer->timers), "Failed to destroy the timeout timer");
88    }
89
90    ps_free(&imx_ltimer->ops.malloc_ops, sizeof(imx_ltimer), imx_ltimer);
91}
92
93static int create_ltimer(ltimer_t *ltimer, ps_io_ops_t ops)
94{
95    assert(ltimer != NULL);
96    ltimer->get_time = get_time;
97    ltimer->get_resolution = get_resolution;
98    ltimer->set_timeout = set_timeout;
99    ltimer->reset = reset;
100    ltimer->destroy = destroy;
101
102    int error = ps_calloc(&ops.malloc_ops, 1, sizeof(imx_ltimer_t), &ltimer->data);
103    if (error) {
104        return error;
105    }
106    assert(ltimer->data != NULL);
107
108    return 0;
109}
110
111int ltimer_default_init(ltimer_t *ltimer, ps_io_ops_t ops, ltimer_callback_fn_t callback, void *callback_token)
112{
113    int error = create_ltimer(ltimer, ops);
114    if (error) {
115        return error;
116    }
117
118    imx_ltimer_t *imx_ltimer = ltimer->data;
119
120    imx_ltimer->ops = ops;
121
122    error = imx_init_timestamp(&imx_ltimer->timers, ops, callback, callback_token);
123    if (error) {
124        ZF_LOGE("Failed to init timestamp timer");
125        ltimer_destroy(ltimer);
126        return error;
127    }
128
129    imx_ltimer->timestamp_initialised = true;
130
131    imx_start_timestamp(&imx_ltimer->timers);
132
133    error = imx_init_timeout(&imx_ltimer->timers, ops, callback, callback_token);
134    if (error) {
135        ZF_LOGE("Failed to init timeout timer");
136        ltimer_destroy(ltimer);
137        return error;
138    }
139    imx_ltimer->timeout_initialised = true;
140
141    /* success! */
142    return 0;
143}
144
145/* This function is intended to be deleted,
146 * this is just left here for now so that stuff can compile */
147int ltimer_default_describe(ltimer_t *ltimer, ps_io_ops_t ops)
148{
149    ZF_LOGE("get_(nth/num)_(irqs/pmems) are not valid");
150    return EINVAL;
151}
152