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, <imer->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