1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 26260fb04SPeter Tyser /* 36260fb04SPeter Tyser * (C) Copyright 2007 Michal Simek 46260fb04SPeter Tyser * 56260fb04SPeter Tyser * Michal SIMEK <monstr@monstr.eu> 66260fb04SPeter Tyser */ 76260fb04SPeter Tyser 86260fb04SPeter Tyser #include <common.h> 99aa65cabSMichal Simek #include <fdtdec.h> 106260fb04SPeter Tyser #include <asm/microblaze_timer.h> 116260fb04SPeter Tyser #include <asm/microblaze_intc.h> 126260fb04SPeter Tyser 139aa65cabSMichal Simek DECLARE_GLOBAL_DATA_PTR; 149aa65cabSMichal Simek 156260fb04SPeter Tyser volatile int timestamp = 0; 16bcbb046bSMichal Simek microblaze_timer_t *tmr; 176260fb04SPeter Tyser 186260fb04SPeter Tyser ulong get_timer (ulong base) 196260fb04SPeter Tyser { 20bcbb046bSMichal Simek if (tmr) 21bcbb046bSMichal Simek return timestamp - base; 22bcbb046bSMichal Simek return timestamp++ - base; 236260fb04SPeter Tyser } 246260fb04SPeter Tyser 25779bf42cSMichal Simek void __udelay(unsigned long usec) 26779bf42cSMichal Simek { 27bcbb046bSMichal Simek u32 i; 28779bf42cSMichal Simek 29bcbb046bSMichal Simek if (tmr) { 30779bf42cSMichal Simek i = get_timer(0); 31779bf42cSMichal Simek while ((get_timer(0) - i) < (usec / 1000)) 32779bf42cSMichal Simek ; 33779bf42cSMichal Simek } 34bcbb046bSMichal Simek } 35779bf42cSMichal Simek 369d242745SMichal Simek #ifndef CONFIG_SPL_BUILD 37bcbb046bSMichal Simek static void timer_isr(void *arg) 386260fb04SPeter Tyser { 396260fb04SPeter Tyser timestamp++; 406260fb04SPeter Tyser tmr->control = tmr->control | TIMER_INTERRUPT; 416260fb04SPeter Tyser } 426260fb04SPeter Tyser 435bbcb6cfSMichal Simek int timer_init (void) 446260fb04SPeter Tyser { 45bcbb046bSMichal Simek int irq = -1; 46bcbb046bSMichal Simek u32 preload = 0; 47bcbb046bSMichal Simek u32 ret = 0; 489aa65cabSMichal Simek const void *blob = gd->fdt_blob; 499aa65cabSMichal Simek int node = 0; 509aa65cabSMichal Simek u32 cell[2]; 519aa65cabSMichal Simek 529aa65cabSMichal Simek debug("TIMER: Initialization\n"); 539aa65cabSMichal Simek 549aa65cabSMichal Simek node = fdt_node_offset_by_compatible(blob, node, 559aa65cabSMichal Simek "xlnx,xps-timer-1.00.a"); 569aa65cabSMichal Simek if (node != -1) { 579aa65cabSMichal Simek fdt_addr_t base = fdtdec_get_addr(blob, node, "reg"); 589aa65cabSMichal Simek if (base == FDT_ADDR_T_NONE) 599aa65cabSMichal Simek return -1; 609aa65cabSMichal Simek 619aa65cabSMichal Simek debug("TIMER: Base addr %lx\n", base); 629aa65cabSMichal Simek tmr = (microblaze_timer_t *)base; 639aa65cabSMichal Simek 649aa65cabSMichal Simek ret = fdtdec_get_int_array(blob, node, "interrupts", 659aa65cabSMichal Simek cell, ARRAY_SIZE(cell)); 669aa65cabSMichal Simek if (ret) 679aa65cabSMichal Simek return ret; 689aa65cabSMichal Simek 699aa65cabSMichal Simek irq = cell[0]; 709aa65cabSMichal Simek debug("TIMER: IRQ %x\n", irq); 719aa65cabSMichal Simek 729aa65cabSMichal Simek preload = fdtdec_get_int(blob, node, "clock-frequency", 0); 739aa65cabSMichal Simek preload /= CONFIG_SYS_HZ; 749aa65cabSMichal Simek } else { 759aa65cabSMichal Simek return node; 769aa65cabSMichal Simek } 779aa65cabSMichal Simek 78bcbb046bSMichal Simek if (tmr && preload && irq >= 0) { 79bcbb046bSMichal Simek tmr->loadreg = preload; 806260fb04SPeter Tyser tmr->control = TIMER_INTERRUPT | TIMER_RESET; 81bcbb046bSMichal Simek tmr->control = TIMER_ENABLE | TIMER_ENABLE_INTR |\ 82bcbb046bSMichal Simek TIMER_RELOAD | TIMER_DOWN_COUNT; 834769be21SGraeme Russ timestamp = 0; 84bcbb046bSMichal Simek ret = install_interrupt_handler (irq, timer_isr, (void *)tmr); 85bcbb046bSMichal Simek if (ret) 86bcbb046bSMichal Simek tmr = NULL; 87bcbb046bSMichal Simek } 88bcbb046bSMichal Simek /* No problem if timer is not found/initialized */ 895bbcb6cfSMichal Simek return 0; 906260fb04SPeter Tyser } 919d242745SMichal Simek #else 929d242745SMichal Simek int timer_init(void) 939d242745SMichal Simek { 949d242745SMichal Simek return 0; 959d242745SMichal Simek } 969d242745SMichal Simek #endif 97b9f0b730SStephan Linz 98b9f0b730SStephan Linz /* 99b9f0b730SStephan Linz * This function is derived from PowerPC code (read timebase as long long). 100b9f0b730SStephan Linz * On Microblaze it just returns the timer value. 101b9f0b730SStephan Linz */ 102b9f0b730SStephan Linz unsigned long long get_ticks(void) 103b9f0b730SStephan Linz { 104b9f0b730SStephan Linz return get_timer(0); 105b9f0b730SStephan Linz } 106b9f0b730SStephan Linz 107b9f0b730SStephan Linz /* 108b9f0b730SStephan Linz * This function is derived from PowerPC code (timebase clock frequency). 109b9f0b730SStephan Linz * On Microblaze it returns the number of timer ticks per second. 110b9f0b730SStephan Linz */ 111b9f0b730SStephan Linz ulong get_tbclk(void) 112b9f0b730SStephan Linz { 113b9f0b730SStephan Linz return CONFIG_SYS_HZ; 114b9f0b730SStephan Linz } 115