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#include <stdio.h> 14#include <assert.h> 15#include <errno.h> 16#include <utils/util.h> 17#include <platsupport/timer.h> 18#include <platsupport/fdt.h> 19#include <platsupport/plat/timer.h> 20#include <utils/frequency.h> 21 22#include "../../ltimer.h" 23 24#define USER_MODE BIT(1) 25#define UNMASKED_INT BIT(2) 26#define TCLR_STARTTIMER BIT(0) 27#define TISR_IRQ_CLEAR BIT(0) 28 29//debug method 30static void print_regs(rk_t *rk) 31{ 32 printf("load_count0 >> 0x%08x\n", rk->hw->load_count0); 33 printf("load_count1 >> 0x%08x\n", rk->hw->load_count1); 34 printf("current_cnt_lowbits >> 0x%08x\n", rk->hw->current_value0); 35 printf("current_cnt_highbits >> 0x%08x\n", rk->hw->current_value1); 36 printf("load_count2 >> 0x%08x\n", rk->hw->load_count2); 37 printf("load_count3 >> 0x%08x\n", rk->hw->load_count3); 38 printf("interrupt_status >> 0x%08x\n", rk->hw->interrupt_status); 39 printf("control_register >> 0x%08x\n", rk->hw->control_register); 40} 41 42int rk_stop(rk_t *rk) 43{ 44 if (rk == NULL) { 45 return EINVAL; 46 } 47 48 rk->hw->control_register = 0; 49 return 0; 50} 51 52uint64_t rk_get_time(rk_t *rk) 53{ 54 if (rk == NULL) { 55 return EINVAL; 56 } 57 uint32_t val1 = rk->hw->current_value1; 58 uint32_t val2 = rk->hw->current_value0; 59 if (val1 != rk->hw->current_value1) { 60 val1 = rk->hw->current_value1; 61 val2 = rk->hw->current_value0; 62 } 63 64 uint64_t time = 0; 65 time = val1; 66 time <<= 32; 67 time |= val2; 68 return ((uint64_t)((time) * NS_IN_S) / 24000000ull); 69} 70 71int rk_start_timestamp_timer(rk_t *rk) 72{ 73 assert(rk != NULL); 74 assert(rk->user_cb_event == LTIMER_OVERFLOW_EVENT); 75 76 rk->hw->control_register = 0; 77 78 //set timer to count up monotonically 79 rk->hw->load_count0 = 0xffffffff; 80 rk->hw->load_count1 = 0xffffffff; 81 82 rk->hw->control_register |= UNMASKED_INT | TCLR_STARTTIMER; 83 return 0; 84} 85 86int rk_set_timeout(rk_t *rk, uint64_t ns, bool periodic) 87{ 88 if (rk == NULL) { 89 return EINVAL; 90 } 91 /* disable timer */ 92 rk->hw->control_register = 0; 93 94 /* timer mode */ 95 uint32_t tclrFlags = periodic ? 0 : USER_MODE; 96 97 /* load timer count */ 98 uint64_t ticks = freq_ns_and_hz_to_cycles(ns, 24000000ull); 99 rk->hw->load_count0 = (uint32_t)(ticks & 0xffffffff); 100 rk->hw->load_count1 = (ticks >> 32); 101 102 /* enable timer with configs */ 103 rk->hw->control_register |= TCLR_STARTTIMER | UNMASKED_INT | tclrFlags; 104 return 0; 105} 106 107static void rk_handle_irq(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data) 108{ 109 assert(data != NULL); 110 rk_t *rk = data; 111 112 /* ack any pending irqs */ 113 rk->hw->interrupt_status = 1; 114 115 ZF_LOGF_IF(acknowledge_fn(ack_data), "Failed to acknowledge the timer's interrupts"); 116 if (rk->user_cb_fn) { 117 rk->user_cb_fn(rk->user_cb_token, rk->user_cb_event); 118 } 119} 120 121bool rk_pending_match(rk_t *rk) 122{ 123 return rk->hw->interrupt_status & TISR_IRQ_CLEAR; 124} 125 126void rk_destroy(rk_t *rk) 127{ 128 int error; 129 if (rk->irq_id != PS_INVALID_IRQ_ID) { 130 error = ps_irq_unregister(&rk->ops.irq_ops, rk->irq_id); 131 ZF_LOGF_IF(error, "Failed to unregister IRQ"); 132 } 133 if (rk->hw != NULL) { 134 rk_stop(rk); 135 } 136 if (rk->rk_map_base != NULL) { 137 /* use base because rk_map is adjusted based on whether secondary */ 138 ps_pmem_unmap(&rk->ops, rk->pmem, (void *) rk->rk_map_base); 139 } 140} 141 142static int irq_index_walker(ps_irq_t irq, unsigned curr_num, size_t num_irqs, void *token) 143{ 144 rk_t *rk = token; 145 146 if (RK_IRQ_CHOICE == curr_num) { 147 irq_id_t registered_id = ps_irq_register(&rk->ops.irq_ops, irq, rk_handle_irq, rk); 148 if (registered_id >= 0) { 149 rk->irq_id = registered_id; 150 rk->irq = irq; 151 } else { 152 /* Bail on error */ 153 return registered_id; 154 } 155 } 156 157 return 0; 158} 159 160int rk_init(rk_t *rk, ps_io_ops_t ops, rk_config_t config) 161{ 162 int error; 163 164 if (rk == NULL) { 165 ZF_LOGE("rk cannot be null"); 166 return EINVAL; 167 } 168 169 rk->ops = ops; 170 rk->user_cb_fn = config.user_cb_fn; 171 rk->user_cb_token = config.user_cb_token; 172 rk->user_cb_event = config.user_cb_event; 173 174 ps_fdt_cookie_t *cookie = NULL; 175 error = ps_fdt_read_path(&ops.io_fdt, &ops.malloc_ops, config.fdt_path, &cookie); 176 if (error) { 177 ZF_LOGE("rockpro64 timer failed to read path (%d, %s)", error, config.fdt_path); 178 return error; 179 } 180 181 rk->rk_map_base = ps_fdt_index_map_register(&ops, cookie, RK_REG_CHOICE, &rk->pmem); 182 if (rk->rk_map_base == NULL) { 183 ZF_LOGE("rockpro64 timer failed to map registers"); 184 return ENODEV; 185 } 186 187 error = ps_fdt_walk_irqs(&ops.io_fdt, cookie, irq_index_walker, rk); 188 if (error) { 189 ZF_LOGE("rockpro64 timer failed to register irqs (%d)", error); 190 return error; 191 } 192 193 rk->irq_id = ps_fdt_cleanup_cookie(&ops.malloc_ops, cookie); 194 if (rk->irq_id) { 195 ZF_LOGE("rockpro64 timer to clean up cookie (%d)", error); 196 return rk->irq_id; 197 } 198 199 rk->hw = rk->rk_map_base; 200 201 return 0; 202} 203 204/* initialise rk using the base address of rkp, so that we do not attempt to map 205 * that base address again but instead re-use it. */ 206int rk_init_secondary(rk_t *rk, rk_t *rkp, ps_io_ops_t ops, rk_config_t config) 207{ 208 int error; 209 210 if (rk == NULL || rkp == NULL) { 211 ZF_LOGE("rk or rkp cannot be null"); 212 return EINVAL; 213 } 214 215 rk->ops = ops; 216 rk->user_cb_fn = config.user_cb_fn; 217 rk->user_cb_token = config.user_cb_token; 218 rk->user_cb_event = config.user_cb_event; 219 220 /* so that destroy does not try to unmap twice */ 221 rk->rk_map_base = NULL; 222 /* just like dmt, rockpro64 has another timer in the same page at 0x20 offset */ 223 rk->hw = (void *)((uintptr_t) rkp->rk_map_base) + 0x20; 224 /* similarly, the IRQ for this secondary timer is offset by 1 */ 225 rk->irq_id = PS_INVALID_IRQ_ID; 226 ps_irq_t irq2 = { .type = PS_INTERRUPT, .irq.number = rkp->irq.irq.number + 1 }; 227 irq_id_t irq2_id = ps_irq_register(&ops.irq_ops, irq2, rk_handle_irq, rk); 228 if (irq2_id < 0) { 229 ZF_LOGE("Failed to register secondary irq for rk timer"); 230 return irq2_id; 231 } 232 rk->irq_id = irq2_id; 233 234 return 0; 235} 236