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/* Implementation of a logical timer for omap platforms
13 *
14 * We use two GPTS: one for the time and relative timeouts, the other
15 * for absolute timeouts.
16 */
17#include <platsupport/timer.h>
18#include <platsupport/ltimer.h>
19#include <platsupport/mach/gpt.h>
20#include <platsupport/pmem.h>
21#include <utils/util.h>
22
23typedef struct {
24    gpt_t abs_gpt;
25    gpt_t rel_gpt;
26    ps_io_ops_t ops;
27} omap_ltimer_t;
28
29static int get_time(void *data, uint64_t *time)
30{
31    assert(data != NULL);
32    assert(time != NULL);
33
34    omap_ltimer_t *omap_ltimer = data;
35    *time = abs_gpt_get_time(&omap_ltimer->abs_gpt);
36    return 0;
37}
38
39static int get_resolution(void *data, uint64_t *resolution)
40{
41    return ENOSYS;
42}
43
44static int set_timeout(void *data, uint64_t ns, timeout_type_t type)
45{
46    assert(data != NULL);
47    omap_ltimer_t *omap_ltimer = data;
48
49    if (type == TIMEOUT_ABSOLUTE) {
50        uint64_t time = abs_gpt_get_time(&omap_ltimer->abs_gpt);
51        if (ns <= time) {
52            return ETIME;
53        }
54        ns -= time;
55    }
56
57    if (ns >= gpt_get_max()) {
58        if (type == TIMEOUT_PERIODIC) {
59            ZF_LOGW("Timeout too big for periodic timeout on this platform");
60            return EINVAL;
61        } else {
62            /* cap it, caller can deal with earlier interrupts */
63            ns = gpt_get_max();
64        }
65    }
66
67    return rel_gpt_set_timeout(&omap_ltimer->rel_gpt, ns, type == TIMEOUT_PERIODIC);
68}
69
70static int reset(void *data)
71{
72    assert(data != NULL);
73    omap_ltimer_t *omap_ltimer = data;
74
75    gpt_stop(&omap_ltimer->abs_gpt);
76    gpt_stop(&omap_ltimer->rel_gpt);
77
78    gpt_start(&omap_ltimer->abs_gpt);
79    gpt_start(&omap_ltimer->rel_gpt);
80
81    return 0;
82}
83
84static void destroy(void *data)
85{
86    assert(data != NULL);
87    omap_ltimer_t *omap_ltimer = data;
88    gpt_destroy(&omap_ltimer->abs_gpt);
89    gpt_destroy(&omap_ltimer->rel_gpt);
90    ps_free(&omap_ltimer->ops.malloc_ops, sizeof(omap_ltimer_t), omap_ltimer);
91}
92
93int ltimer_default_init(ltimer_t *ltimer, ps_io_ops_t ops, ltimer_callback_fn_t callback, void *callback_token)
94{
95    int error;
96
97    if (ltimer == NULL) {
98        return EINVAL;
99    }
100
101    ltimer->get_time = get_time;
102    ltimer->get_resolution = get_resolution;
103    ltimer->set_timeout = set_timeout;
104    ltimer->reset = reset;
105    ltimer->destroy = destroy;
106    ltimer->get_num_pmems = NULL;
107    ltimer->get_num_irqs = NULL;
108    ltimer->get_nth_pmem = NULL;
109    ltimer->get_nth_irq = NULL;
110
111    error = ps_calloc(&ops.malloc_ops, 1, sizeof(omap_ltimer_t), &ltimer->data);
112    if (error) {
113        return error;
114    }
115    assert(ltimer->data != NULL);
116    omap_ltimer_t *omap_ltimer = ltimer->data;
117    omap_ltimer->ops = ops;
118
119    error = gpt_create(&omap_ltimer->abs_gpt, ops, GPT1_DEVICE_PATH, callback, callback_token);
120    if (error) {
121        ZF_LOGE("Failed to create abs gpt timer");
122        return error;
123    }
124
125    error = gpt_create(&omap_ltimer->rel_gpt, ops, GPT2_DEVICE_PATH, callback, callback_token);
126    if (error) {
127        ZF_LOGE("Failed to create rel gpt timer");
128        return error;
129    }
130
131    /* setup gpt */
132    gpt_config_t config = {
133        .prescaler = 1,
134    };
135
136    /* intitialise gpt for getting the time */
137    error = abs_gpt_init(&omap_ltimer->abs_gpt, config);
138    if (error) {
139        ZF_LOGE("Failed to init gpt");
140        destroy(ltimer->data);
141        return error;
142    }
143
144    error = rel_gpt_init(&omap_ltimer->rel_gpt, config);
145    if (error) {
146        destroy(ltimer->data);
147        ZF_LOGE("Failed to init gpt");
148        return error;
149    }
150
151    gpt_start(&omap_ltimer->abs_gpt);
152    gpt_start(&omap_ltimer->rel_gpt);
153
154    /* success! */
155    return 0;
156}
157
158/* This function is intended to be deleted,
159 * this is just left here for now so that stuff can compile */
160int ltimer_default_describe(ltimer_t *ltimer, ps_io_ops_t ops)
161{
162    ZF_LOGE("get_(nth/num)_(irqs/pmems) are not valid");
163    return EINVAL;
164}
165