1/* 2 * Copyright 2020, 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/* Minimal implementation of a logical timer for zynq 14 * 15 * Does not implement some functions yet. 16 */ 17#include <platsupport/timer.h> 18#include <platsupport/ltimer.h> 19#include <platsupport/plat/timer.h> 20 21#include <utils/util.h> 22 23#include "../../ltimer.h" 24 25/* Use ttc0_timer1 for timeouts/sleep */ 26#define TTC_TIMEOUT TTC0_TIMER1 27/* Use ttc1_timer1 to keep running for timestamp/gettime */ 28#define TTC_TIMESTAMP TTC1_TIMER1 29 30#define N_TTCS 2 31#define TIMEOUT_IDX 0 32#define TIMESTAMP_IDX 1 33 34typedef struct { 35 ttc_t ttcs[N_TTCS]; 36 ps_io_ops_t ops; 37 bool timeout_initialised; 38 bool timestamp_initialised; 39} ttc_ltimer_t; 40 41static int get_time(void *data, uint64_t *time) 42{ 43 assert(data != NULL); 44 assert(time != NULL); 45 ttc_ltimer_t *ttc_ltimer = data; 46 *time = ttc_get_time(&ttc_ltimer->ttcs[TIMESTAMP_IDX]); 47 return 0; 48} 49 50static int get_resolution(void *data, uint64_t *resolution) 51{ 52 return ENOSYS; 53} 54 55static int set_timeout(void *data, uint64_t ns, timeout_type_t type) 56{ 57 assert(data != NULL); 58 ttc_ltimer_t *ttc_ltimer = data; 59 60 if (type == TIMEOUT_ABSOLUTE) { 61 uint64_t time = 0; 62 get_time(data, &time); 63 if (ns <= time) { 64 return ETIME; 65 } else { 66 ns -= time; 67 } 68 } 69 70 return ttc_set_timeout(&ttc_ltimer->ttcs[TIMEOUT_IDX], ns, type == TIMEOUT_PERIODIC); 71} 72 73static int reset(void *data) 74{ 75 assert(data != NULL); 76 ttc_ltimer_t *ttc_ltimer = data; 77 78 /* reset the timers */ 79 ttc_stop(&ttc_ltimer->ttcs[TIMEOUT_IDX]); 80 ttc_start(&ttc_ltimer->ttcs[TIMEOUT_IDX]); 81 ttc_stop(&ttc_ltimer->ttcs[TIMESTAMP_IDX]); 82 ttc_start(&ttc_ltimer->ttcs[TIMESTAMP_IDX]); 83 84 return 0; 85} 86 87static void destroy(void *data) 88{ 89 assert(data); 90 91 ttc_ltimer_t *ttc_ltimer = data; 92 93 int error = 0; 94 95 if (ttc_ltimer->timeout_initialised) { 96 error = ttc_destroy(&ttc_ltimer->ttcs[TIMEOUT_IDX]); 97 ZF_LOGF_IF(error, "Failed to de-allocate the timeout timer"); 98 } 99 100 if (ttc_ltimer->timestamp_initialised) { 101 error = ttc_destroy(&ttc_ltimer->ttcs[TIMESTAMP_IDX]); 102 ZF_LOGF_IF(error, "Failed to de-allocate the timestamp timer"); 103 } 104 105 ps_free(&ttc_ltimer->ops.malloc_ops, sizeof(ttc_ltimer), ttc_ltimer); 106} 107 108static int create_ltimer(ltimer_t *ltimer, ps_io_ops_t ops) 109{ 110 ltimer->get_time = get_time; 111 ltimer->get_resolution = get_resolution; 112 ltimer->set_timeout = set_timeout; 113 ltimer->reset = reset; 114 ltimer->destroy = destroy; 115 116 int error = ps_calloc(&ops.malloc_ops, 1, sizeof(ttc_ltimer_t), <imer->data); 117 if (error) { 118 return error; 119 } 120 assert(ltimer->data != NULL); 121 122 return 0; 123} 124 125int ltimer_default_init(ltimer_t *ltimer, ps_io_ops_t ops, ltimer_callback_fn_t callback, void *callback_token) 126{ 127 int error = create_ltimer(ltimer, ops); 128 if (error) { 129 return error; 130 } 131 132 ttc_ltimer_t *ttc_ltimer = ltimer->data; 133 ttc_ltimer->ops = ops; 134 135 ttc_config_t config = { 136 .io_ops = ops, 137 .user_callback = callback, 138 .user_callback_token = callback_token, 139 .id = TTC_TIMEOUT, 140 }; 141 142 ttc_config_t config_timestamp = { 143 .io_ops = ops, 144 .user_callback = callback, 145 .user_callback_token = callback_token, 146 .is_timestamp = true, 147 .id = TTC_TIMESTAMP, 148 }; 149 150 error = ttc_init(&ttc_ltimer->ttcs[TIMEOUT_IDX], config); 151 if (error) { 152 ZF_LOGE("Failed to init the timeout timer"); 153 ltimer_destroy(ltimer); 154 return error; 155 } 156 157 ttc_ltimer->timeout_initialised = true; 158 159 error = ttc_start(&ttc_ltimer->ttcs[TIMEOUT_IDX]); 160 if (error) { 161 ZF_LOGE("Failed to start the timeout timer"); 162 ltimer_destroy(ltimer); 163 return error; 164 } 165 166 /* set the second ttc to be a timestamp counter */ 167 error = ttc_init(&ttc_ltimer->ttcs[TIMESTAMP_IDX], config_timestamp); 168 if (error) { 169 ZF_LOGE("Failed to init the timestamp timer"); 170 ltimer_destroy(ltimer); 171 return error; 172 } 173 174 ttc_ltimer->timestamp_initialised = true; 175 176 ttc_freerun(&ttc_ltimer->ttcs[TIMESTAMP_IDX]); 177 error = ttc_start(&ttc_ltimer->ttcs[TIMESTAMP_IDX]); 178 if (error) { 179 ZF_LOGE("Failed to start the timestamp timer"); 180 ltimer_destroy(ltimer); 181 return error; 182 } 183 184 return 0; 185} 186 187/* This function is intended to be deleted, 188 * this is just left here for now so that stuff can compile */ 189int ltimer_default_describe(ltimer_t *ltimer, ps_io_ops_t ops) 190{ 191 ZF_LOGE("get_(nth/num)_(irqs/pmems) are not valid"); 192 return EINVAL; 193} 194