1/* 2 * Copyright 2017, 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#include <stdio.h> 13#include <assert.h> 14 15#include <utils/util.h> 16#include <utils/time.h> 17 18#include <platsupport/ltimer.h> 19#include <platsupport/plat/rtc.h> 20#include <platsupport/plat/dmt.h> 21#include <platsupport/io.h> 22 23#include "../../ltimer.h" 24 25/* 26 * We use two dm timers: one to keep track of an absolute time, the other for timeouts. 27 */ 28/* hikey dualtimers have 2 timers per frame, we just use one from each */ 29typedef struct { 30 dmt_t dmt_timeout; 31 dmt_t dmt_timestamp; 32 ps_io_ops_t ops; 33} hikey_ltimer_t; 34 35static int get_time(void *data, uint64_t *time) 36{ 37 hikey_ltimer_t *hikey_ltimer = data; 38 assert(data != NULL); 39 assert(time != NULL); 40 41 *time = dmt_get_time(&hikey_ltimer->dmt_timestamp); 42 return 0; 43} 44 45int set_timeout(void *data, uint64_t ns, timeout_type_t type) 46{ 47 if (type == TIMEOUT_ABSOLUTE) { 48 uint64_t time; 49 int error = get_time(data, &time); 50 if (error) { 51 return error; 52 } 53 if (time > ns) { 54 return ETIME; 55 } 56 ns -= time; 57 } 58 59 hikey_ltimer_t *hikey_ltimer = data; 60 return dmt_set_timeout(&hikey_ltimer->dmt_timeout, ns, type == TIMEOUT_PERIODIC, true); 61} 62 63static int reset(void *data) 64{ 65 hikey_ltimer_t *hikey_ltimer = data; 66 /* restart the rtc */ 67 dmt_stop(&hikey_ltimer->dmt_timeout); 68 dmt_start(&hikey_ltimer->dmt_timeout); 69 return 0; 70} 71 72static void destroy(void *data) 73{ 74 assert(data != NULL); 75 hikey_ltimer_t *hikey_ltimer = data; 76 /* NOTE: Note that timeout is primary, timestamp is secondary. 77 * this means that timeout holds the region mapping. 78 * We must first destroy timestamp before destroying timeout 79 * so that the region is freed last. */ 80 dmt_destroy(&hikey_ltimer->dmt_timestamp); 81 dmt_destroy(&hikey_ltimer->dmt_timeout); 82 ps_free(&hikey_ltimer->ops.malloc_ops, sizeof(hikey_ltimer_t), hikey_ltimer); 83} 84 85int ltimer_default_init(ltimer_t *ltimer, ps_io_ops_t ops, ltimer_callback_fn_t callback, void *callback_token) 86{ 87 int error; 88 89 if (ltimer == NULL) { 90 ZF_LOGE("ltimer cannot be NULL"); 91 return EINVAL; 92 } 93 94 error = create_ltimer_simple( 95 ltimer, ops, sizeof(hikey_ltimer_t), 96 get_time, set_timeout, reset, destroy 97 ); 98 if (error) { 99 ZF_LOGE("Failed to create ltimer for hikey"); 100 return error; 101 } 102 103 hikey_ltimer_t *hikey_ltimer = ltimer->data; 104 hikey_ltimer->ops = ops; 105 106 /* set up a DMT for timeouts */ 107 dmt_config_t dmt_config = { 108 .fdt_path = DMT_PATH, 109 .user_cb_fn = callback, 110 .user_cb_token = callback_token, 111 .user_cb_event = LTIMER_TIMEOUT_EVENT 112 }; 113 114 error = dmt_init(&hikey_ltimer->dmt_timeout, ops, dmt_config); 115 if (error) { 116 ZF_LOGE("Failed to init dmt timeout timer"); 117 destroy(hikey_ltimer); 118 return error; 119 } 120 121 error = dmt_start(&hikey_ltimer->dmt_timeout); 122 if (error) { 123 ZF_LOGE("Failed to start dmt timeout timer"); 124 destroy(hikey_ltimer); 125 return error; 126 } 127 128 /* set up a DMT for timestamps */ 129 dmt_config.user_cb_event = LTIMER_OVERFLOW_EVENT; 130 131 error = dmt_init_secondary(&hikey_ltimer->dmt_timestamp, &hikey_ltimer->dmt_timeout, ops, dmt_config); 132 if (error) { 133 ZF_LOGE("Failed to init dmt secondary for timestamps"); 134 destroy(hikey_ltimer); 135 return error; 136 } 137 138 error = dmt_start(&hikey_ltimer->dmt_timestamp); 139 if (error) { 140 ZF_LOGE("Failed to start dmt timestamp timer"); 141 destroy(hikey_ltimer); 142 return error; 143 } 144 145 error = dmt_set_timeout_ticks(&hikey_ltimer->dmt_timestamp, UINT32_MAX, true, true); 146 if (error) { 147 ZF_LOGE("Failed to set ticks for dmt timestamp timer"); 148 destroy(hikey_ltimer); 149 return error; 150 } 151 152 return 0; 153} 154 155/* This function is intended to be deleted, 156 * this is just left here for now so that stuff can compile */ 157int ltimer_default_describe(ltimer_t *ltimer, ps_io_ops_t ops) 158{ 159 ZF_LOGE("get_(nth/num)_(irqs/pmems) are not valid"); 160 return EINVAL; 161} 162