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/* Implementation of a logical timer for omap platforms 13 * 14 * We use two GPTS: one for the time and relative timeouts, the other 15 * for absolute timeouts. 16 */ 17#include <platsupport/timer.h> 18#include <platsupport/ltimer.h> 19#include <platsupport/mach/gpt.h> 20#include <platsupport/pmem.h> 21#include <utils/util.h> 22 23typedef struct { 24 gpt_t abs_gpt; 25 gpt_t rel_gpt; 26 ps_io_ops_t ops; 27} omap_ltimer_t; 28 29static int get_time(void *data, uint64_t *time) 30{ 31 assert(data != NULL); 32 assert(time != NULL); 33 34 omap_ltimer_t *omap_ltimer = data; 35 *time = abs_gpt_get_time(&omap_ltimer->abs_gpt); 36 return 0; 37} 38 39static int get_resolution(void *data, uint64_t *resolution) 40{ 41 return ENOSYS; 42} 43 44static int set_timeout(void *data, uint64_t ns, timeout_type_t type) 45{ 46 assert(data != NULL); 47 omap_ltimer_t *omap_ltimer = data; 48 49 if (type == TIMEOUT_ABSOLUTE) { 50 uint64_t time = abs_gpt_get_time(&omap_ltimer->abs_gpt); 51 if (ns <= time) { 52 return ETIME; 53 } 54 ns -= time; 55 } 56 57 if (ns >= gpt_get_max()) { 58 if (type == TIMEOUT_PERIODIC) { 59 ZF_LOGW("Timeout too big for periodic timeout on this platform"); 60 return EINVAL; 61 } else { 62 /* cap it, caller can deal with earlier interrupts */ 63 ns = gpt_get_max(); 64 } 65 } 66 67 return rel_gpt_set_timeout(&omap_ltimer->rel_gpt, ns, type == TIMEOUT_PERIODIC); 68} 69 70static int reset(void *data) 71{ 72 assert(data != NULL); 73 omap_ltimer_t *omap_ltimer = data; 74 75 gpt_stop(&omap_ltimer->abs_gpt); 76 gpt_stop(&omap_ltimer->rel_gpt); 77 78 gpt_start(&omap_ltimer->abs_gpt); 79 gpt_start(&omap_ltimer->rel_gpt); 80 81 return 0; 82} 83 84static void destroy(void *data) 85{ 86 assert(data != NULL); 87 omap_ltimer_t *omap_ltimer = data; 88 gpt_destroy(&omap_ltimer->abs_gpt); 89 gpt_destroy(&omap_ltimer->rel_gpt); 90 ps_free(&omap_ltimer->ops.malloc_ops, sizeof(omap_ltimer_t), omap_ltimer); 91} 92 93int ltimer_default_init(ltimer_t *ltimer, ps_io_ops_t ops, ltimer_callback_fn_t callback, void *callback_token) 94{ 95 int error; 96 97 if (ltimer == NULL) { 98 return EINVAL; 99 } 100 101 ltimer->get_time = get_time; 102 ltimer->get_resolution = get_resolution; 103 ltimer->set_timeout = set_timeout; 104 ltimer->reset = reset; 105 ltimer->destroy = destroy; 106 ltimer->get_num_pmems = NULL; 107 ltimer->get_num_irqs = NULL; 108 ltimer->get_nth_pmem = NULL; 109 ltimer->get_nth_irq = NULL; 110 111 error = ps_calloc(&ops.malloc_ops, 1, sizeof(omap_ltimer_t), <imer->data); 112 if (error) { 113 return error; 114 } 115 assert(ltimer->data != NULL); 116 omap_ltimer_t *omap_ltimer = ltimer->data; 117 omap_ltimer->ops = ops; 118 119 error = gpt_create(&omap_ltimer->abs_gpt, ops, GPT1_DEVICE_PATH, callback, callback_token); 120 if (error) { 121 ZF_LOGE("Failed to create abs gpt timer"); 122 return error; 123 } 124 125 error = gpt_create(&omap_ltimer->rel_gpt, ops, GPT2_DEVICE_PATH, callback, callback_token); 126 if (error) { 127 ZF_LOGE("Failed to create rel gpt timer"); 128 return error; 129 } 130 131 /* setup gpt */ 132 gpt_config_t config = { 133 .prescaler = 1, 134 }; 135 136 /* intitialise gpt for getting the time */ 137 error = abs_gpt_init(&omap_ltimer->abs_gpt, config); 138 if (error) { 139 ZF_LOGE("Failed to init gpt"); 140 destroy(ltimer->data); 141 return error; 142 } 143 144 error = rel_gpt_init(&omap_ltimer->rel_gpt, config); 145 if (error) { 146 destroy(ltimer->data); 147 ZF_LOGE("Failed to init gpt"); 148 return error; 149 } 150 151 gpt_start(&omap_ltimer->abs_gpt); 152 gpt_start(&omap_ltimer->rel_gpt); 153 154 /* success! */ 155 return 0; 156} 157 158/* This function is intended to be deleted, 159 * this is just left here for now so that stuff can compile */ 160int ltimer_default_describe(ltimer_t *ltimer, ps_io_ops_t ops) 161{ 162 ZF_LOGE("get_(nth/num)_(irqs/pmems) are not valid"); 163 return EINVAL; 164} 165