1*1168d2ddSPhilipp Tomsich /* 2*1168d2ddSPhilipp Tomsich * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH 3*1168d2ddSPhilipp Tomsich * 4*1168d2ddSPhilipp Tomsich * SPDX-License-Identifier: GPL-2.0+ 5*1168d2ddSPhilipp Tomsich */ 6*1168d2ddSPhilipp Tomsich 7*1168d2ddSPhilipp Tomsich #include <common.h> 8*1168d2ddSPhilipp Tomsich #include <dm.h> 9*1168d2ddSPhilipp Tomsich #include <mapmem.h> 10*1168d2ddSPhilipp Tomsich #include <asm/arch/timer.h> 11*1168d2ddSPhilipp Tomsich #include <dt-structs.h> 12*1168d2ddSPhilipp Tomsich #include <timer.h> 13*1168d2ddSPhilipp Tomsich #include <asm/io.h> 14*1168d2ddSPhilipp Tomsich 15*1168d2ddSPhilipp Tomsich DECLARE_GLOBAL_DATA_PTR; 16*1168d2ddSPhilipp Tomsich 17*1168d2ddSPhilipp Tomsich #if CONFIG_IS_ENABLED(OF_PLATDATA) 18*1168d2ddSPhilipp Tomsich struct rockchip_timer_plat { 19*1168d2ddSPhilipp Tomsich struct dtd_rockchip_rk3368_timer dtd; 20*1168d2ddSPhilipp Tomsich }; 21*1168d2ddSPhilipp Tomsich #endif 22*1168d2ddSPhilipp Tomsich 23*1168d2ddSPhilipp Tomsich /* Driver private data. Contains timer id. Could be either 0 or 1. */ 24*1168d2ddSPhilipp Tomsich struct rockchip_timer_priv { 25*1168d2ddSPhilipp Tomsich struct rk_timer *timer; 26*1168d2ddSPhilipp Tomsich }; 27*1168d2ddSPhilipp Tomsich 28*1168d2ddSPhilipp Tomsich static int rockchip_timer_get_count(struct udevice *dev, u64 *count) 29*1168d2ddSPhilipp Tomsich { 30*1168d2ddSPhilipp Tomsich struct rockchip_timer_priv *priv = dev_get_priv(dev); 31*1168d2ddSPhilipp Tomsich uint64_t timebase_h, timebase_l; 32*1168d2ddSPhilipp Tomsich uint64_t cntr; 33*1168d2ddSPhilipp Tomsich 34*1168d2ddSPhilipp Tomsich timebase_l = readl(&priv->timer->timer_curr_value0); 35*1168d2ddSPhilipp Tomsich timebase_h = readl(&priv->timer->timer_curr_value1); 36*1168d2ddSPhilipp Tomsich 37*1168d2ddSPhilipp Tomsich /* timers are down-counting */ 38*1168d2ddSPhilipp Tomsich cntr = timebase_h << 32 | timebase_l; 39*1168d2ddSPhilipp Tomsich *count = ~0ull - cntr; 40*1168d2ddSPhilipp Tomsich return 0; 41*1168d2ddSPhilipp Tomsich } 42*1168d2ddSPhilipp Tomsich 43*1168d2ddSPhilipp Tomsich static int rockchip_clk_ofdata_to_platdata(struct udevice *dev) 44*1168d2ddSPhilipp Tomsich { 45*1168d2ddSPhilipp Tomsich #if !CONFIG_IS_ENABLED(OF_PLATDATA) 46*1168d2ddSPhilipp Tomsich struct rockchip_timer_priv *priv = dev_get_priv(dev); 47*1168d2ddSPhilipp Tomsich 48*1168d2ddSPhilipp Tomsich priv->timer = (struct rk_timer *)devfdt_get_addr(dev); 49*1168d2ddSPhilipp Tomsich #endif 50*1168d2ddSPhilipp Tomsich 51*1168d2ddSPhilipp Tomsich return 0; 52*1168d2ddSPhilipp Tomsich } 53*1168d2ddSPhilipp Tomsich 54*1168d2ddSPhilipp Tomsich static int rockchip_timer_start(struct udevice *dev) 55*1168d2ddSPhilipp Tomsich { 56*1168d2ddSPhilipp Tomsich struct rockchip_timer_priv *priv = dev_get_priv(dev); 57*1168d2ddSPhilipp Tomsich const uint64_t reload_val = ~0uLL; 58*1168d2ddSPhilipp Tomsich const uint32_t reload_val_l = reload_val & 0xffffffff; 59*1168d2ddSPhilipp Tomsich const uint32_t reload_val_h = reload_val >> 32; 60*1168d2ddSPhilipp Tomsich 61*1168d2ddSPhilipp Tomsich /* disable timer and reset all control */ 62*1168d2ddSPhilipp Tomsich writel(0, &priv->timer->timer_ctrl_reg); 63*1168d2ddSPhilipp Tomsich /* write reload value */ 64*1168d2ddSPhilipp Tomsich writel(reload_val_l, &priv->timer->timer_load_count0); 65*1168d2ddSPhilipp Tomsich writel(reload_val_h, &priv->timer->timer_load_count1); 66*1168d2ddSPhilipp Tomsich /* enable timer */ 67*1168d2ddSPhilipp Tomsich writel(1, &priv->timer->timer_ctrl_reg); 68*1168d2ddSPhilipp Tomsich 69*1168d2ddSPhilipp Tomsich return 0; 70*1168d2ddSPhilipp Tomsich } 71*1168d2ddSPhilipp Tomsich 72*1168d2ddSPhilipp Tomsich static int rockchip_timer_probe(struct udevice *dev) 73*1168d2ddSPhilipp Tomsich { 74*1168d2ddSPhilipp Tomsich #if CONFIG_IS_ENABLED(OF_PLATDATA) 75*1168d2ddSPhilipp Tomsich struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); 76*1168d2ddSPhilipp Tomsich struct rockchip_timer_priv *priv = dev_get_priv(dev); 77*1168d2ddSPhilipp Tomsich struct rockchip_timer_plat *plat = dev_get_platdata(dev); 78*1168d2ddSPhilipp Tomsich 79*1168d2ddSPhilipp Tomsich priv->timer = map_sysmem(plat->dtd.reg[1], plat->dtd.reg[3]); 80*1168d2ddSPhilipp Tomsich uc_priv->clock_rate = plat->dtd.clock_frequency; 81*1168d2ddSPhilipp Tomsich #endif 82*1168d2ddSPhilipp Tomsich 83*1168d2ddSPhilipp Tomsich return rockchip_timer_start(dev); 84*1168d2ddSPhilipp Tomsich } 85*1168d2ddSPhilipp Tomsich 86*1168d2ddSPhilipp Tomsich static const struct timer_ops rockchip_timer_ops = { 87*1168d2ddSPhilipp Tomsich .get_count = rockchip_timer_get_count, 88*1168d2ddSPhilipp Tomsich }; 89*1168d2ddSPhilipp Tomsich 90*1168d2ddSPhilipp Tomsich static const struct udevice_id rockchip_timer_ids[] = { 91*1168d2ddSPhilipp Tomsich { .compatible = "rockchip,rk3368-timer" }, 92*1168d2ddSPhilipp Tomsich {} 93*1168d2ddSPhilipp Tomsich }; 94*1168d2ddSPhilipp Tomsich 95*1168d2ddSPhilipp Tomsich U_BOOT_DRIVER(arc_timer) = { 96*1168d2ddSPhilipp Tomsich .name = "rockchip_rk3368_timer", 97*1168d2ddSPhilipp Tomsich .id = UCLASS_TIMER, 98*1168d2ddSPhilipp Tomsich .of_match = rockchip_timer_ids, 99*1168d2ddSPhilipp Tomsich .probe = rockchip_timer_probe, 100*1168d2ddSPhilipp Tomsich .ops = &rockchip_timer_ops, 101*1168d2ddSPhilipp Tomsich .flags = DM_FLAG_PRE_RELOC, 102*1168d2ddSPhilipp Tomsich .priv_auto_alloc_size = sizeof(struct rockchip_timer_priv), 103*1168d2ddSPhilipp Tomsich #if CONFIG_IS_ENABLED(OF_PLATDATA) 104*1168d2ddSPhilipp Tomsich .platdata_auto_alloc_size = sizeof(struct rockchip_timer_plat), 105*1168d2ddSPhilipp Tomsich #endif 106*1168d2ddSPhilipp Tomsich .ofdata_to_platdata = rockchip_clk_ofdata_to_platdata, 107*1168d2ddSPhilipp Tomsich }; 108