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 13#include <stdio.h> 14#include <assert.h> 15#include <errno.h> 16#include <stdlib.h> 17 18#include <utils/util.h> 19 20#include <platsupport/timer.h> 21#include <platsupport/mach/pwm.h> 22#include <platsupport/ltimer.h> 23#include <platsupport/fdt.h> 24 25#if defined CONFIG_PLAT_EXYNOS5 26#define CLK_FREQ 66ull /* MHz */ 27#else 28#define CLK_FREQ 100ull /* MHz */ 29#endif 30 31#define T4_ENABLE BIT(20) 32#define T4_MANUALRELOAD BIT(21) 33#define T4_AUTORELOAD BIT(22) 34 35#define T0_ENABLE BIT(0) 36#define T0_MANUALRELOAD BIT(1) 37#define T0_AUTORELOAD BIT(3) 38 39/* TCFG0 */ 40#define T234_PRESCALE(x) ((x) << 8) 41#define T234_PRESCALE_MASK T234_PRESCALE(0xff) 42#define T01_PRESCALE(x) (x) 43#define T01_PRESCALE_MASK T01_PRESCALE(0xff) 44 45/* TCFG1 */ 46#define T4_DIVISOR(x) ((x) << 16) 47#define T4_DIVISOR_MASK T4_DIVISOR(0xf) 48#define T0_DIVISOR(x) (x) 49#define T0_DIVISOR_MASK T0_DIVISOR(0xf) 50 51/* TINT_CSTAT */ 52#define INT_ENABLE(x) BIT(x) 53#define INT_STAT(x) BIT((x) + 5) 54#define INT_ENABLE_ALL ( INT_ENABLE(0) | INT_ENABLE(1) | INT_ENABLE(2) \ 55 | INT_ENABLE(3) | INT_ENABLE(4) ) 56 57/* How many interrupts must be defined in device tree */ 58#define PWM_FDT_IRQ_COUNT (5u) 59 60static void configure_timeout(pwm_t *pwm, uint64_t ns, int timer_number, bool periodic) 61{ 62 assert((timer_number == 0) | (timer_number == 4)); // Only these timers are currently supported 63 uint32_t v; 64 65 /* Disable timer. */ 66 if (timer_number == 4) { 67 pwm->pwm_map->tcon &= ~(T4_ENABLE); 68 } else { 69 pwm->pwm_map->tcon &= ~(T0_ENABLE); 70 } 71 72 /* Enable interrupt on overflow. */ 73 if (timer_number == 4) { 74 pwm->pwm_map->tint_cstat |= INT_ENABLE(4); 75 } else { 76 pwm->pwm_map->tint_cstat |= INT_ENABLE(0); 77 } 78 79 /* clear the scale */ 80 if (timer_number == 4) { 81 pwm->pwm_map->tcfg0 &= ~(T234_PRESCALE_MASK); 82 pwm->pwm_map->tcfg1 &= ~(T4_DIVISOR_MASK); 83 } else { 84 pwm->pwm_map->tcfg0 &= ~(T01_PRESCALE_MASK); 85 pwm->pwm_map->tcfg1 &= ~(T0_DIVISOR_MASK); 86 } 87 88 /* Calculate the scale and reload values. */ 89 uint32_t div = 0; /* Not implemented */ 90 uint64_t ticks = (ns * CLK_FREQ) / 1000; 91 uint32_t prescale = ticks >> (32); 92 uint32_t cnt = ticks / (prescale + 1) / (BIT(div)); 93 94 assert(prescale <= 0xff); /* if this fails, we need to implement div */ 95 assert(div <= 0xf); 96 97 /* set scale and reload values */ 98 if (timer_number == 4) { 99 pwm->pwm_map->tcfg0 |= T234_PRESCALE(prescale); 100 pwm->pwm_map->tcfg1 &= T4_DIVISOR(div); 101 pwm->pwm_map->tcntB4 = cnt; 102 } else { 103 pwm->pwm_map->tcfg0 |= T01_PRESCALE(prescale); 104 pwm->pwm_map->tcfg1 &= T0_DIVISOR(div); 105 pwm->pwm_map->tcntB0 = cnt; 106 } 107 108 /* load tcntB4 by flushing the double buffer */ 109 if (timer_number == 4) { 110 pwm->pwm_map->tcon |= T4_MANUALRELOAD; 111 pwm->pwm_map->tcon &= ~(T4_MANUALRELOAD); 112 } else { 113 pwm->pwm_map->tcon |= T0_MANUALRELOAD; 114 pwm->pwm_map->tcon &= ~(T0_MANUALRELOAD); 115 } 116 117 /* Clear pending overflows. */ 118 v = pwm->pwm_map->tint_cstat; 119 if (timer_number == 4) { 120 v = (v & INT_ENABLE_ALL) | INT_STAT(4); 121 } else { 122 v = (v & INT_ENABLE_ALL) | INT_STAT(0); 123 } 124 pwm->pwm_map->tint_cstat = v; 125 126 if (periodic) { 127 if (timer_number == 4) { 128 pwm->pwm_map->tcon |= T4_AUTORELOAD; 129 } else { 130 pwm->pwm_map->tcon |= T0_AUTORELOAD; 131 } 132 } 133} 134 135/* 136 * We will use timer 0 for timekeeping overflows, timer 4 for user-requested timeouts. 137 */ 138static int pwm_start(pwm_t *pwm) 139{ 140 /* start the timer */ 141 pwm->pwm_map->tcon |= T4_ENABLE; 142 143 /* Start timer0 for get_time */ 144 configure_timeout(pwm, NS_IN_S, 0, true); 145 /* Set autoreload and start the timer. */ 146 pwm->pwm_map->tcon |= T0_ENABLE; 147 pwm->time_h = 0; 148 149 return 0; 150} 151 152static int pwm_stop(pwm_t *pwm) 153{ 154 /* Disable timer. */ 155 pwm->pwm_map->tcon &= ~(T4_ENABLE | T0_ENABLE); 156 157 /* load tcntB4 and tcntB0 by flushing the double buffer */ 158 pwm->pwm_map->tcon |= T4_MANUALRELOAD; 159 pwm->pwm_map->tcon &= ~(T4_MANUALRELOAD); 160 pwm->pwm_map->tcon |= T0_MANUALRELOAD; 161 pwm->pwm_map->tcon &= ~(T0_MANUALRELOAD); 162 163 /* disable interrupts */ 164 pwm->pwm_map->tint_cstat &= ~(INT_ENABLE(4) | INT_ENABLE(0)); 165 166 /* ack interrupt */ 167 pwm->pwm_map->tint_cstat |= ~(INT_STAT(4) | INT_STAT(0)); 168 169 return 0; 170} 171 172int pwm_set_timeout(pwm_t *pwm, uint64_t ns, bool periodic) 173{ 174 configure_timeout(pwm, ns, 4, periodic); 175 176 /* start the timer. */ 177 pwm->pwm_map->tcon |= T4_ENABLE; 178 179 return 0; 180} 181 182/* 183 * Check if a timekeeping overflow interrupt is pending, and increment counter if so. 184 */ 185static void pwm_check_timekeeping_overflow(pwm_t *pwm) 186{ 187 uint32_t v = pwm->pwm_map->tint_cstat; 188 if (v & INT_STAT(0)) { 189 pwm->time_h++; 190 v = (v & INT_ENABLE_ALL) | INT_STAT(0); 191 } 192 pwm->pwm_map->tint_cstat = v; 193} 194 195static void pwm_handle_irq0(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data) 196{ 197 pwm_t *pwm = data; 198 pwm_check_timekeeping_overflow(data); 199 ZF_LOGF_IF(acknowledge_fn(ack_data), "Failed to acknowledge the timer's interrupts"); 200 if (pwm->user_cb_fn) { 201 pwm->user_cb_fn(pwm->user_cb_token, LTIMER_OVERFLOW_EVENT); 202 } 203} 204 205static void pwm_handle_irq4(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data) 206{ 207 pwm_t *pwm = data; 208 uint32_t v = pwm->pwm_map->tint_cstat; 209 if (v & INT_STAT(4)) { 210 v = (v & INT_ENABLE_ALL) | INT_STAT(4); 211 } 212 pwm->pwm_map->tint_cstat = v; 213 ZF_LOGF_IF(acknowledge_fn(ack_data), "Failed to acknowledge the timer's interrupts"); 214 if (pwm->user_cb_fn) { 215 pwm->user_cb_fn(pwm->user_cb_token, LTIMER_TIMEOUT_EVENT); 216 } 217} 218 219uint64_t pwm_get_time(pwm_t *pwm) 220{ 221 uint64_t hi = pwm->time_h; 222 uint64_t time_l = ((pwm->pwm_map->tcntO0 / CLK_FREQ) * 1000.0); // Clk is in MHz 223 pwm_check_timekeeping_overflow(pwm); // Ensure the time is up to date 224 if (hi != pwm->time_h) { 225 time_l = ((pwm->pwm_map->tcntO0 / CLK_FREQ) * 1000.0); 226 } 227 return pwm->time_h * NS_IN_S + (NS_IN_S - time_l); 228} 229 230static int pwm_walk_registers(pmem_region_t pmem, unsigned curr_num, size_t num_regs, void *token) 231{ 232 pwm_t *pwm = token; 233 void *mmio_vaddr; 234 235 /* assert only one entry in device tree node */ 236 if (curr_num != 0 || num_regs != 1) { 237 ZF_LOGE("Too many registers in timer device tree node"); 238 return -ENODEV; 239 } 240 241 mmio_vaddr = ps_pmem_map(&pwm->ops, pmem, false, PS_MEM_NORMAL); 242 if (mmio_vaddr == NULL) { 243 ZF_LOGE("Unable to map timer device"); 244 return -ENODEV; 245 } 246 247 pwm->pwm_map = mmio_vaddr; 248 pwm->pmem = pmem; 249 250 return 0; 251} 252 253static int pwm_walk_irqs(ps_irq_t irq, unsigned curr_num, size_t num_irqs, void *token) 254{ 255 pwm_t *pwm = token; 256 irq_id_t irq_id; 257 258 /* the device has 5 timers */ 259 if (num_irqs != PWM_FDT_IRQ_COUNT) { 260 ZF_LOGE("Expected interrupts count of 5, have %zu", num_irqs); 261 return -ENODEV; 262 } 263 264 /* we only support 0 and 4, so ignore others */ 265 switch (curr_num) { 266 case 0: 267 irq_id = ps_irq_register(&pwm->ops.irq_ops, irq, pwm_handle_irq0, pwm); 268 if (irq_id < 0) { 269 ZF_LOGE("Unable to register timer irq0"); 270 return irq_id; 271 } 272 pwm->t0_irq = irq_id; 273 break; 274 275 case 4: 276 irq_id = ps_irq_register(&pwm->ops.irq_ops, irq, pwm_handle_irq4, pwm); 277 if (irq_id < 0) { 278 ZF_LOGE("Unable to register timer irq4"); 279 return irq_id; 280 } 281 pwm->t4_irq = irq_id; 282 break; 283 284 default: 285 break; 286 } 287 288 return 0; 289} 290 291void pwm_destroy(pwm_t *pwm) 292{ 293 int error; 294 295 /* pre-set INVALID_IRQ_ID before init and do not run if not initialised */ 296 if (pwm->t0_irq != PS_INVALID_IRQ_ID) { 297 error = ps_irq_unregister(&pwm->ops.irq_ops, pwm->t0_irq); 298 ZF_LOGE_IF(error, "Unable to un-register timer irq0") 299 } 300 if (pwm->t4_irq != PS_INVALID_IRQ_ID) { 301 error = ps_irq_unregister(&pwm->ops.irq_ops, pwm->t4_irq); 302 ZF_LOGE_IF(error, "Unable to un-register timer irq4") 303 } 304 305 /* check if pwm_map is NULL and do not run if not initialised */ 306 if (pwm->pwm_map != NULL) { 307 error = pwm_stop(pwm); 308 ZF_LOGE_IF(error, "Unable to stop timer pwm") 309 310 ps_pmem_unmap(&pwm->ops, pwm->pmem, (void *) pwm->pwm_map); 311 } 312} 313 314int pwm_init(pwm_t *pwm, ps_io_ops_t ops, char *fdt_path, ltimer_callback_fn_t user_cb_fn, void *user_cb_token) 315{ 316 int error; 317 ps_fdt_cookie_t *fdt_cookie; 318 319 if (pwm == NULL || fdt_path == NULL) { 320 ZF_LOGE("Invalid (null) arguments to pwm timer init"); 321 return -EINVAL; 322 } 323 324 pwm->ops = ops; 325 pwm->user_cb_fn = user_cb_fn; 326 pwm->user_cb_token = user_cb_token; 327 328 /* these are only valid if the callbacks complete successfully */ 329 pwm->pwm_map = NULL; /* if set, implies pmem_region_t valid */ 330 pwm->t0_irq = PS_INVALID_IRQ_ID; 331 pwm->t4_irq = PS_INVALID_IRQ_ID; 332 333 error = ps_fdt_read_path(&ops.io_fdt, &ops.malloc_ops, fdt_path, &fdt_cookie); 334 if (error) { 335 ZF_LOGE("Unable to read fdt for pwm timer"); 336 pwm_destroy(pwm); 337 return error; 338 } 339 340 error = ps_fdt_walk_registers(&ops.io_fdt, fdt_cookie, pwm_walk_registers, pwm); 341 if (error) { 342 ZF_LOGE("Unable to walk fdt registers for pwm timer"); 343 pwm_destroy(pwm); 344 return error; 345 } 346 347 error = ps_fdt_walk_irqs(&ops.io_fdt, fdt_cookie, pwm_walk_irqs, pwm); 348 if (error) { 349 ZF_LOGE("Unable to walk fdt irqs for pwm timer"); 350 pwm_destroy(pwm); 351 return error; 352 } 353 354 error = ps_fdt_cleanup_cookie(&ops.malloc_ops, fdt_cookie); 355 if (error) { 356 ZF_LOGE("Unable to free fdt cookie for pwm timer"); 357 pwm_destroy(pwm); 358 return error; 359 } 360 361 /* callback section of pwm_t should be set up properly */ 362 363 error = pwm_start(pwm); 364 if (error) { 365 ZF_LOGE("Unable to configure start pwm timer"); 366 pwm_destroy(pwm); 367 return error; 368 } 369 370 return 0; 371} 372 373int pwm_reset(pwm_t *pwm) 374{ 375 int error; 376 377 error = pwm_stop(pwm); 378 if (error) { 379 ZF_LOGE("Unable to configure stop pwm timer (reset)"); 380 return error; 381 } 382 383 error = pwm_start(pwm); 384 if (error) { 385 ZF_LOGE("Unable to configure start pwm timer (reset)"); 386 return error; 387 } 388 389 return 0; 390} 391