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#include <platsupport/ltimer.h>
14#include <platsupport/irq.h>
15#include <platsupport/fdt.h>
16
17/* Per-platform ltimer IRQ handling function type */
18typedef int (*ltimer_handle_irq_fn_t)(void *data, ps_irq_t *irq);
19
20typedef struct {
21    ltimer_t *ltimer;
22    ps_irq_t *irq;
23    ltimer_handle_irq_fn_t irq_handler;
24} timer_callback_data_t;
25
26/*
27 * This is a simple wrapper around the per-platform ltimer IRQ handling function.
28 *
29 * This is called as a callback function from the IRQ interface when the user asks it to handle IRQs.
30 *
31 * Note that this wrapper assumes that the interrupts are level triggered.
32 */
33static inline void handle_irq_wrapper(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data)
34{
35    assert(data);
36
37    timer_callback_data_t *callback_data = (timer_callback_data_t *) data;
38
39    ltimer_t *ltimer = callback_data->ltimer;
40    ps_irq_t *irq = callback_data->irq;
41    ltimer_handle_irq_fn_t irq_handler = callback_data->irq_handler;
42
43    int UNUSED error = irq_handler(ltimer->data, irq);
44    assert(!error);
45
46    error = acknowledge_fn(ack_data);
47    assert(!error);
48}
49
50static int helper_fdt_alloc_simple(
51    ps_io_ops_t *ops, char *fdt_path,
52    unsigned reg_choice, unsigned irq_choice,
53    void **vmap, pmem_region_t *pmem, irq_id_t *irq_id,
54    irq_callback_fn_t handler, void *handler_token
55)
56{
57    assert(fdt_path != NULL);
58    assert(vmap != NULL && pmem != NULL && irq_id != NULL);
59
60    int error;
61    void *temp_vmap;
62    pmem_region_t temp_pmem;
63    irq_id_t temp_irq_id;
64
65    *vmap = NULL;
66    *irq_id = PS_INVALID_IRQ_ID;
67
68    /* Gather FDT info */
69    ps_fdt_cookie_t *cookie = NULL;
70    error = ps_fdt_read_path(&ops->io_fdt, &ops->malloc_ops, fdt_path, &cookie);
71    if (error) {
72        ZF_LOGE("Simple FDT helper failed to read path (%d, %s)", error, fdt_path);
73        return error;
74    }
75
76    temp_vmap = ps_fdt_index_map_register(ops, cookie, reg_choice, &temp_pmem);
77    if (temp_vmap == NULL) {
78        ZF_LOGE("Simple FDT helper failed to map registers");
79        return ENODEV;
80    }
81
82    temp_irq_id = ps_fdt_index_register_irq(ops, cookie, irq_choice, handler, handler_token);
83    if (temp_irq_id <= PS_INVALID_IRQ_ID) {
84        ZF_LOGE("Simple FDT helper failed to register irqs (%d)", temp_irq_id);
85        return temp_irq_id;
86    }
87
88    error = ps_fdt_cleanup_cookie(&ops->malloc_ops, cookie);
89    if (error) {
90        ZF_LOGE("Simple FDT helper failed to clean up cookie (%d)", error);
91        return error;
92    }
93
94    *vmap = temp_vmap;
95    *pmem = temp_pmem;
96    *irq_id = temp_irq_id;
97
98    return 0;
99}
100
101static int get_resolution_dummy(void *data, uint64_t *resolution)
102{
103    return ENOSYS;
104}
105
106static int create_ltimer_simple(
107    ltimer_t *ltimer, ps_io_ops_t ops, size_t sz,
108    int (*get_time)(void *data, uint64_t *time),
109    int (*set_timeout)(void *data, uint64_t ns, timeout_type_t type),
110    int (*reset)(void *data),
111    void (*destroy)(void *data)
112)
113{
114    assert(ltimer != NULL);
115
116    ltimer->get_time = get_time;
117    ltimer->get_resolution = get_resolution_dummy;
118    ltimer->set_timeout = set_timeout;
119    ltimer->reset = reset;
120    ltimer->destroy = destroy;
121    ltimer->get_nth_irq = NULL;
122    ltimer->get_nth_pmem = NULL;
123    ltimer->get_num_irqs = NULL;
124    ltimer->get_num_pmems = NULL;
125
126    int error = ps_calloc(&ops.malloc_ops, 1, sz, &ltimer->data);
127    if (error) {
128        ZF_LOGE("Unable to allocate ltimer data");
129        return error;
130    }
131    assert(ltimer->data != NULL);
132
133    return 0;
134}
135