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