1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Designware APB Timer driver 4 * 5 * Copyright (C) 2018 Marek Vasut <marex@denx.de> 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <clk.h> 11 #include <timer.h> 12 13 #include <asm/io.h> 14 #include <asm/arch/timer.h> 15 16 #define DW_APB_LOAD_VAL 0x0 17 #define DW_APB_CURR_VAL 0x4 18 #define DW_APB_CTRL 0x8 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 struct dw_apb_timer_priv { 23 fdt_addr_t regs; 24 }; 25 26 static int dw_apb_timer_get_count(struct udevice *dev, u64 *count) 27 { 28 struct dw_apb_timer_priv *priv = dev_get_priv(dev); 29 30 /* 31 * The DW APB counter counts down, but this function 32 * requires the count to be incrementing. Invert the 33 * result. 34 */ 35 *count = ~readl(priv->regs + DW_APB_CURR_VAL); 36 37 return 0; 38 } 39 40 static int dw_apb_timer_probe(struct udevice *dev) 41 { 42 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); 43 struct dw_apb_timer_priv *priv = dev_get_priv(dev); 44 struct clk clk; 45 int ret; 46 47 ret = clk_get_by_index(dev, 0, &clk); 48 if (ret) 49 return ret; 50 51 uc_priv->clock_rate = clk_get_rate(&clk); 52 53 clk_free(&clk); 54 55 /* init timer */ 56 writel(0xffffffff, priv->regs + DW_APB_LOAD_VAL); 57 writel(0xffffffff, priv->regs + DW_APB_CURR_VAL); 58 setbits_le32(priv->regs + DW_APB_CTRL, 0x3); 59 60 return 0; 61 } 62 63 static int dw_apb_timer_ofdata_to_platdata(struct udevice *dev) 64 { 65 struct dw_apb_timer_priv *priv = dev_get_priv(dev); 66 67 priv->regs = dev_read_addr(dev); 68 69 return 0; 70 } 71 72 static const struct timer_ops dw_apb_timer_ops = { 73 .get_count = dw_apb_timer_get_count, 74 }; 75 76 static const struct udevice_id dw_apb_timer_ids[] = { 77 { .compatible = "snps,dw-apb-timer" }, 78 {} 79 }; 80 81 U_BOOT_DRIVER(dw_apb_timer) = { 82 .name = "dw_apb_timer", 83 .id = UCLASS_TIMER, 84 .ops = &dw_apb_timer_ops, 85 .probe = dw_apb_timer_probe, 86 .flags = DM_FLAG_PRE_RELOC, 87 .of_match = dw_apb_timer_ids, 88 .ofdata_to_platdata = dw_apb_timer_ofdata_to_platdata, 89 .priv_auto_alloc_size = sizeof(struct dw_apb_timer_priv), 90 }; 91