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 beagle bone 14 * 15 * We use the 1 DMT for timeouts and 1 for a millisecond tick. 16 */ 17#include <platsupport/timer.h> 18#include <platsupport/ltimer.h> 19#include <platsupport/plat/timer.h> 20#include <utils/frequency.h> 21 22#include <utils/util.h> 23 24#include "../../ltimer.h" 25 26typedef struct { 27 dmt_t dmt_timeout; 28 dmt_t dmt_timestamp; 29 ps_io_ops_t ops; 30} dmt_ltimer_t; 31 32static int get_time(void *data, uint64_t *time) 33{ 34 assert(data != NULL); 35 assert(time != NULL); 36 dmt_ltimer_t *dmt_ltimer = data; 37 38 *time = dmt_get_time(&dmt_ltimer->dmt_timestamp); 39 return 0; 40} 41 42static int get_resolution(void *data, uint64_t *resolution) 43{ 44 *resolution = NS_IN_MS; 45 return 0; 46} 47 48static int set_timeout(void *data, uint64_t ns, timeout_type_t type) 49{ 50 assert(data != NULL); 51 dmt_ltimer_t *dmt_ltimer = data; 52 53 if (type == TIMEOUT_ABSOLUTE) { 54 uint64_t current_time = 0; 55 int error = get_time(data, ¤t_time); 56 assert(error == 0); 57 if (ns < current_time) { 58 return ETIME; 59 } 60 ns -= current_time; 61 } 62 63 return dmt_set_timeout(&dmt_ltimer->dmt_timeout, ns, type == TIMEOUT_PERIODIC); 64} 65 66static int reset(void *data) 67{ 68 assert(data != NULL); 69 dmt_ltimer_t *dmt_ltimer = data; 70 dmt_stop(&dmt_ltimer->dmt_timeout); 71 dmt_stop(&dmt_ltimer->dmt_timestamp); 72 dmt_start(&dmt_ltimer->dmt_timeout); 73 dmt_start(&dmt_ltimer->dmt_timestamp); 74 return 0; 75} 76 77static void destroy(void *data) 78{ 79 assert(data != NULL); 80 dmt_ltimer_t *dmt_ltimer = data; 81 dmt_destroy(&dmt_ltimer->dmt_timeout); 82 dmt_destroy(&dmt_ltimer->dmt_timestamp); 83 ps_free(&dmt_ltimer->ops.malloc_ops, sizeof(dmt_ltimer_t), dmt_ltimer); 84} 85 86int ltimer_default_init(ltimer_t *ltimer, ps_io_ops_t ops, ltimer_callback_fn_t callback, void *callback_token) 87{ 88 int error; 89 90 error = create_ltimer_simple( 91 ltimer, ops, sizeof(dmt_ltimer_t), 92 get_time, set_timeout, reset, destroy 93 ); 94 if (error) { 95 ZF_LOGE("Failed to create ltimer"); 96 return error; 97 } 98 ltimer->get_resolution = get_resolution; 99 100 dmt_ltimer_t *dmt_ltimer = ltimer->data; 101 dmt_ltimer->ops = ops; 102 103 dmt_config_t dmt_config = { 104 .user_cb_fn = callback, 105 .user_cb_token = callback_token, 106 .user_cb_event = LTIMER_OVERFLOW_EVENT, 107 .fdt_path = DMTIMER2_PATH, 108 }; 109 110 error = dmt_init(&dmt_ltimer->dmt_timestamp, ops, dmt_config); 111 if (error) { 112 ZF_LOGE("Failed to init dmt (TIMEKEEPING)"); 113 destroy(dmt_ltimer); 114 return error; 115 } 116 117 error = dmt_start_ticking_timer(&dmt_ltimer->dmt_timestamp); 118 if (error) { 119 ZF_LOGE("Failed to start dmt (TIMEKEEPING)"); 120 destroy(dmt_ltimer); 121 return error; 122 } 123 124 dmt_config.fdt_path = DMTIMER3_PATH; 125 dmt_config.user_cb_event = LTIMER_TIMEOUT_EVENT; 126 127 error = dmt_init(&dmt_ltimer->dmt_timeout, ops, dmt_config); 128 if (error) { 129 ZF_LOGE("Failed to init dmt (TIMEOUT)"); 130 destroy(dmt_ltimer); 131 return error; 132 } 133 134 error = dmt_start(&dmt_ltimer->dmt_timeout); 135 if (error) { 136 ZF_LOGE("Failed to start dmt (TIMEOUT)"); 137 destroy(dmt_ltimer); 138 return error; 139 } 140 141 return 0; 142} 143 144/* This function is intended to be deleted, 145 * this is just left here for now so that stuff can compile */ 146int ltimer_default_describe(ltimer_t *ltimer, ps_io_ops_t ops) 147{ 148 ZF_LOGE("get_(nth/num)_(irqs/pmems) are not valid"); 149 return EINVAL; 150} 151