Home | History | Annotate | Download | only in cpu
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * (C) Copyright 2007 Michal Simek
      4  *
      5  * Michal  SIMEK <monstr (at) monstr.eu>
      6  */
      7 
      8 #include <common.h>
      9 #include <fdtdec.h>
     10 #include <asm/microblaze_timer.h>
     11 #include <asm/microblaze_intc.h>
     12 
     13 DECLARE_GLOBAL_DATA_PTR;
     14 
     15 volatile int timestamp = 0;
     16 microblaze_timer_t *tmr;
     17 
     18 ulong get_timer (ulong base)
     19 {
     20 	if (tmr)
     21 		return timestamp - base;
     22 	return timestamp++ - base;
     23 }
     24 
     25 void __udelay(unsigned long usec)
     26 {
     27 	u32 i;
     28 
     29 	if (tmr) {
     30 		i = get_timer(0);
     31 		while ((get_timer(0) - i) < (usec / 1000))
     32 			;
     33 	}
     34 }
     35 
     36 #ifndef CONFIG_SPL_BUILD
     37 static void timer_isr(void *arg)
     38 {
     39 	timestamp++;
     40 	tmr->control = tmr->control | TIMER_INTERRUPT;
     41 }
     42 
     43 int timer_init (void)
     44 {
     45 	int irq = -1;
     46 	u32 preload = 0;
     47 	u32 ret = 0;
     48 	const void *blob = gd->fdt_blob;
     49 	int node = 0;
     50 	u32 cell[2];
     51 
     52 	debug("TIMER: Initialization\n");
     53 
     54 	node = fdt_node_offset_by_compatible(blob, node,
     55 				"xlnx,xps-timer-1.00.a");
     56 	if (node != -1) {
     57 		fdt_addr_t base = fdtdec_get_addr(blob, node, "reg");
     58 		if (base == FDT_ADDR_T_NONE)
     59 			return -1;
     60 
     61 		debug("TIMER: Base addr %lx\n", base);
     62 		tmr = (microblaze_timer_t *)base;
     63 
     64 		ret = fdtdec_get_int_array(blob, node, "interrupts",
     65 					    cell, ARRAY_SIZE(cell));
     66 		if (ret)
     67 			return ret;
     68 
     69 		irq = cell[0];
     70 		debug("TIMER: IRQ %x\n", irq);
     71 
     72 		preload = fdtdec_get_int(blob, node, "clock-frequency", 0);
     73 		preload /= CONFIG_SYS_HZ;
     74 	} else {
     75 		return node;
     76 	}
     77 
     78 	if (tmr && preload && irq >= 0) {
     79 		tmr->loadreg = preload;
     80 		tmr->control = TIMER_INTERRUPT | TIMER_RESET;
     81 		tmr->control = TIMER_ENABLE | TIMER_ENABLE_INTR |\
     82 					TIMER_RELOAD | TIMER_DOWN_COUNT;
     83 		timestamp = 0;
     84 		ret = install_interrupt_handler (irq, timer_isr, (void *)tmr);
     85 		if (ret)
     86 			tmr = NULL;
     87 	}
     88 	/* No problem if timer is not found/initialized */
     89 	return 0;
     90 }
     91 #else
     92 int timer_init(void)
     93 {
     94 	return 0;
     95 }
     96 #endif
     97 
     98 /*
     99  * This function is derived from PowerPC code (read timebase as long long).
    100  * On Microblaze it just returns the timer value.
    101  */
    102 unsigned long long get_ticks(void)
    103 {
    104 	return get_timer(0);
    105 }
    106 
    107 /*
    108  * This function is derived from PowerPC code (timebase clock frequency).
    109  * On Microblaze it returns the number of timer ticks per second.
    110  */
    111 ulong get_tbclk(void)
    112 {
    113 	return CONFIG_SYS_HZ;
    114 }
    115