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 rockpro64 14 * 15 * We use the 1 rk for timeouts and 1 for a millisecond tick. 16 * 17 * The configuration of timers that we use allows us to map only one page in. 18 */ 19#include <platsupport/timer.h> 20#include <platsupport/ltimer.h> 21#include <platsupport/plat/timer.h> 22#include <utils/util.h> 23 24#include "../../ltimer.h" 25 26typedef struct { 27 rk_t rk_timeout; 28 rk_t rk_timestamp; 29 ps_io_ops_t ops; 30} rk_ltimer_t; 31 32static int get_time(void *data, uint64_t *time) 33{ 34 assert(data != NULL); 35 assert(time != NULL); 36 37 rk_ltimer_t *rk_ltimer = data; 38 *time = rk_get_time(&rk_ltimer->rk_timestamp); 39 return 0; 40} 41 42static int set_timeout(void *data, uint64_t ns, timeout_type_t type) 43{ 44 assert(data != NULL); 45 rk_ltimer_t *rk_ltimer = data; 46 47 if (type == TIMEOUT_ABSOLUTE) { 48 uint64_t current_time = 0; 49 int error = get_time(data, ¤t_time); 50 assert(error == 0); 51 ns -= current_time; 52 } 53 54 return rk_set_timeout(&rk_ltimer->rk_timeout, ns, type == TIMEOUT_PERIODIC); 55} 56 57static int reset(void *data) 58{ 59 assert(data != NULL); 60 rk_ltimer_t *rk_ltimer = data; 61 /* just reset the timeout timer */ 62 rk_stop(&rk_ltimer->rk_timeout); 63 /* no need to start it again, that is done by 64 * set_timeout automatically */ 65 return 0; 66} 67 68static void destroy(void *data) 69{ 70 assert(data != NULL); 71 rk_ltimer_t *rk_ltimer = data; 72 /* NOTE: Note that timeout is primary, timestamp is secondary. 73 * this means that timeout holds the region mapping. 74 * We must first destroy timestamp before destroying timeout 75 * so that the region is freed last. */ 76 rk_destroy(&rk_ltimer->rk_timestamp); 77 rk_destroy(&rk_ltimer->rk_timeout); 78 ps_free(&rk_ltimer->ops.malloc_ops, sizeof(rk_ltimer_t), rk_ltimer); 79} 80 81int ltimer_default_init(ltimer_t *ltimer, ps_io_ops_t ops, ltimer_callback_fn_t callback, void *callback_token) 82{ 83 /* mostly copied from dmt.c */ 84 int error; 85 86 if (ltimer == NULL) { 87 ZF_LOGE("ltimer cannot be NULL"); 88 return EINVAL; 89 } 90 91 error = create_ltimer_simple( 92 ltimer, ops, sizeof(rk_ltimer_t), 93 get_time, set_timeout, reset, destroy 94 ); 95 if (error) { 96 ZF_LOGE("Failed to create ltimer for rk"); 97 return error; 98 } 99 100 rk_ltimer_t *rk_ltimer = ltimer->data; 101 rk_ltimer->ops = ops; 102 103 /* set up a timer for timeouts */ 104 rk_config_t rk_config = { 105 .fdt_path = RK_TIMER_PATH, 106 .user_cb_fn = callback, 107 .user_cb_token = callback_token, 108 .user_cb_event = LTIMER_TIMEOUT_EVENT 109 }; 110 111 error = rk_init(&rk_ltimer->rk_timeout, ops, rk_config); 112 if (error) { 113 ZF_LOGE("Failed to initialise timer (timeout)"); 114 destroy(rk_ltimer); 115 return error; 116 } 117 118 /* no start for timeout timer */ 119 120 /* set up a timer for timestamps */ 121 rk_config.user_cb_event = LTIMER_OVERFLOW_EVENT; 122 123 error = rk_init_secondary(&rk_ltimer->rk_timestamp, &rk_ltimer->rk_timeout, ops, rk_config); 124 if (error) { 125 ZF_LOGE("Failed to initialise timer (timestamp)"); 126 destroy(rk_ltimer); 127 return error; 128 } 129 130 error = rk_start_timestamp_timer(&rk_ltimer->rk_timestamp); 131 if (error) { 132 ZF_LOGE("Failed to start timestamp timer"); 133 destroy(rk_ltimer); 134 return error; 135 } 136 137 return 0; 138} 139 140/* This function is intended to be deleted, 141 * this is just left here for now so that stuff can compile */ 142int ltimer_default_describe(ltimer_t *ltimer, ps_io_ops_t ops) 143{ 144 ZF_LOGE("get_(nth/num)_(irqs/pmems) are not valid"); 145 return EINVAL; 146} 147