1*a54915d8SThomas Chou /* 2*a54915d8SThomas Chou * (C) Copyright 2000-2002 3*a54915d8SThomas Chou * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4*a54915d8SThomas Chou * 5*a54915d8SThomas Chou * (C) Copyright 2004, Psyent Corporation <www.psyent.com> 6*a54915d8SThomas Chou * Scott McNutt <smcnutt@psyent.com> 7*a54915d8SThomas Chou * 8*a54915d8SThomas Chou * SPDX-License-Identifier: GPL-2.0+ 9*a54915d8SThomas Chou */ 10*a54915d8SThomas Chou 11*a54915d8SThomas Chou #include <common.h> 12*a54915d8SThomas Chou #include <dm.h> 13*a54915d8SThomas Chou #include <errno.h> 14*a54915d8SThomas Chou #include <timer.h> 15*a54915d8SThomas Chou #include <asm/io.h> 16*a54915d8SThomas Chou 17*a54915d8SThomas Chou DECLARE_GLOBAL_DATA_PTR; 18*a54915d8SThomas Chou 19*a54915d8SThomas Chou struct altera_timer_regs { 20*a54915d8SThomas Chou u32 status; /* Timer status reg */ 21*a54915d8SThomas Chou u32 control; /* Timer control reg */ 22*a54915d8SThomas Chou u32 periodl; /* Timeout period low */ 23*a54915d8SThomas Chou u32 periodh; /* Timeout period high */ 24*a54915d8SThomas Chou u32 snapl; /* Snapshot low */ 25*a54915d8SThomas Chou u32 snaph; /* Snapshot high */ 26*a54915d8SThomas Chou }; 27*a54915d8SThomas Chou 28*a54915d8SThomas Chou struct altera_timer_platdata { 29*a54915d8SThomas Chou struct altera_timer_regs *regs; 30*a54915d8SThomas Chou unsigned long clock_rate; 31*a54915d8SThomas Chou }; 32*a54915d8SThomas Chou 33*a54915d8SThomas Chou /* control register */ 34*a54915d8SThomas Chou #define ALTERA_TIMER_CONT (1 << 1) /* Continuous mode */ 35*a54915d8SThomas Chou #define ALTERA_TIMER_START (1 << 2) /* Start timer */ 36*a54915d8SThomas Chou #define ALTERA_TIMER_STOP (1 << 3) /* Stop timer */ 37*a54915d8SThomas Chou 38*a54915d8SThomas Chou static int altera_timer_get_count(struct udevice *dev, unsigned long *count) 39*a54915d8SThomas Chou { 40*a54915d8SThomas Chou struct altera_timer_platdata *plat = dev->platdata; 41*a54915d8SThomas Chou struct altera_timer_regs *const regs = plat->regs; 42*a54915d8SThomas Chou u32 val; 43*a54915d8SThomas Chou 44*a54915d8SThomas Chou /* Trigger update */ 45*a54915d8SThomas Chou writel(0x0, ®s->snapl); 46*a54915d8SThomas Chou 47*a54915d8SThomas Chou /* Read timer value */ 48*a54915d8SThomas Chou val = readl(®s->snapl) & 0xffff; 49*a54915d8SThomas Chou val |= (readl(®s->snaph) & 0xffff) << 16; 50*a54915d8SThomas Chou *count = ~val; 51*a54915d8SThomas Chou 52*a54915d8SThomas Chou return 0; 53*a54915d8SThomas Chou } 54*a54915d8SThomas Chou 55*a54915d8SThomas Chou static int altera_timer_probe(struct udevice *dev) 56*a54915d8SThomas Chou { 57*a54915d8SThomas Chou struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); 58*a54915d8SThomas Chou struct altera_timer_platdata *plat = dev->platdata; 59*a54915d8SThomas Chou struct altera_timer_regs *const regs = plat->regs; 60*a54915d8SThomas Chou 61*a54915d8SThomas Chou uc_priv->clock_rate = plat->clock_rate; 62*a54915d8SThomas Chou 63*a54915d8SThomas Chou writel(0, ®s->status); 64*a54915d8SThomas Chou writel(0, ®s->control); 65*a54915d8SThomas Chou writel(ALTERA_TIMER_STOP, ®s->control); 66*a54915d8SThomas Chou 67*a54915d8SThomas Chou writel(0xffff, ®s->periodl); 68*a54915d8SThomas Chou writel(0xffff, ®s->periodh); 69*a54915d8SThomas Chou writel(ALTERA_TIMER_CONT | ALTERA_TIMER_START, ®s->control); 70*a54915d8SThomas Chou 71*a54915d8SThomas Chou return 0; 72*a54915d8SThomas Chou } 73*a54915d8SThomas Chou 74*a54915d8SThomas Chou static int altera_timer_ofdata_to_platdata(struct udevice *dev) 75*a54915d8SThomas Chou { 76*a54915d8SThomas Chou struct altera_timer_platdata *plat = dev_get_platdata(dev); 77*a54915d8SThomas Chou 78*a54915d8SThomas Chou plat->regs = ioremap(dev_get_addr(dev), 79*a54915d8SThomas Chou sizeof(struct altera_timer_regs)); 80*a54915d8SThomas Chou plat->clock_rate = fdtdec_get_int(gd->fdt_blob, dev->of_offset, 81*a54915d8SThomas Chou "clock-frequency", 0); 82*a54915d8SThomas Chou 83*a54915d8SThomas Chou return 0; 84*a54915d8SThomas Chou } 85*a54915d8SThomas Chou 86*a54915d8SThomas Chou static const struct timer_ops altera_timer_ops = { 87*a54915d8SThomas Chou .get_count = altera_timer_get_count, 88*a54915d8SThomas Chou }; 89*a54915d8SThomas Chou 90*a54915d8SThomas Chou static const struct udevice_id altera_timer_ids[] = { 91*a54915d8SThomas Chou { .compatible = "altr,timer-1.0", }, 92*a54915d8SThomas Chou { } 93*a54915d8SThomas Chou }; 94*a54915d8SThomas Chou 95*a54915d8SThomas Chou U_BOOT_DRIVER(altera_timer) = { 96*a54915d8SThomas Chou .name = "altera_timer", 97*a54915d8SThomas Chou .id = UCLASS_TIMER, 98*a54915d8SThomas Chou .of_match = altera_timer_ids, 99*a54915d8SThomas Chou .ofdata_to_platdata = altera_timer_ofdata_to_platdata, 100*a54915d8SThomas Chou .platdata_auto_alloc_size = sizeof(struct altera_timer_platdata), 101*a54915d8SThomas Chou .probe = altera_timer_probe, 102*a54915d8SThomas Chou .ops = &altera_timer_ops, 103*a54915d8SThomas Chou .flags = DM_FLAG_PRE_RELOC, 104*a54915d8SThomas Chou }; 105