1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <dm/ofnode.h> 9 #include <mapmem.h> 10 #include <asm/arch/timer.h> 11 #include <dt-structs.h> 12 #include <timer.h> 13 #include <asm/io.h> 14 15 DECLARE_GLOBAL_DATA_PTR; 16 17 #if CONFIG_IS_ENABLED(OF_PLATDATA) 18 struct rockchip_timer_plat { 19 struct dtd_rockchip_rk3368_timer dtd; 20 }; 21 #endif 22 23 /* Driver private data. Contains timer id. Could be either 0 or 1. */ 24 struct rockchip_timer_priv { 25 struct rk_timer *timer; 26 }; 27 28 static inline int64_t rockchip_timer_get_curr_value(struct rk_timer *timer) 29 { 30 uint64_t timebase_h, timebase_l; 31 uint64_t cntr; 32 33 timebase_l = readl(&timer->timer_curr_value0); 34 timebase_h = readl(&timer->timer_curr_value1); 35 36 cntr = timebase_h << 32 | timebase_l; 37 return cntr; 38 } 39 40 #if CONFIG_IS_ENABLED(BOOTSTAGE) 41 ulong timer_get_boot_us(void) 42 { 43 uint64_t ticks = 0; 44 uint32_t rate; 45 uint64_t us; 46 int ret; 47 48 ret = dm_timer_init(); 49 50 if (!ret) { 51 /* The timer is available */ 52 rate = timer_get_rate(gd->timer); 53 timer_get_count(gd->timer, &ticks); 54 #if !CONFIG_IS_ENABLED(OF_PLATDATA) 55 } else if (ret == -EAGAIN) { 56 /* We have been called so early that the DM is not ready,... */ 57 ofnode node = offset_to_ofnode(-1); 58 struct rk_timer *timer = NULL; 59 60 /* 61 * ... so we try to access the raw timer, if it is specified 62 * via the tick-timer property in /chosen. 63 */ 64 node = ofnode_get_chosen_node("tick-timer"); 65 if (!ofnode_valid(node)) { 66 debug("%s: no /chosen/tick-timer\n", __func__); 67 return 0; 68 } 69 70 timer = (struct rk_timer *)ofnode_get_addr(node); 71 72 /* This timer is down-counting */ 73 ticks = ~0uLL - rockchip_timer_get_curr_value(timer); 74 if (ofnode_read_u32(node, "clock-frequency", &rate)) { 75 debug("%s: could not read clock-frequency\n", __func__); 76 return 0; 77 } 78 #endif 79 } else { 80 return 0; 81 } 82 83 us = (ticks * 1000) / rate; 84 return us; 85 } 86 #endif 87 88 static int rockchip_timer_get_count(struct udevice *dev, u64 *count) 89 { 90 struct rockchip_timer_priv *priv = dev_get_priv(dev); 91 uint64_t cntr = rockchip_timer_get_curr_value(priv->timer); 92 93 /* timers are down-counting */ 94 *count = ~0ull - cntr; 95 return 0; 96 } 97 98 static int rockchip_clk_ofdata_to_platdata(struct udevice *dev) 99 { 100 #if !CONFIG_IS_ENABLED(OF_PLATDATA) 101 struct rockchip_timer_priv *priv = dev_get_priv(dev); 102 103 priv->timer = dev_read_addr_ptr(dev); 104 if (!priv->timer) 105 return -ENOENT; 106 #endif 107 108 return 0; 109 } 110 111 static int rockchip_timer_start(struct udevice *dev) 112 { 113 struct rockchip_timer_priv *priv = dev_get_priv(dev); 114 const uint64_t reload_val = ~0uLL; 115 const uint32_t reload_val_l = reload_val & 0xffffffff; 116 const uint32_t reload_val_h = reload_val >> 32; 117 118 /* don't reinit, if the timer is already running and set up */ 119 if ((readl(&priv->timer->timer_ctrl_reg) & 1) == 1 && 120 (readl(&priv->timer->timer_load_count0) == reload_val_l) && 121 (readl(&priv->timer->timer_load_count1) == reload_val_h)) 122 return 0; 123 124 /* disable timer and reset all control */ 125 writel(0, &priv->timer->timer_ctrl_reg); 126 /* write reload value */ 127 writel(reload_val_l, &priv->timer->timer_load_count0); 128 writel(reload_val_h, &priv->timer->timer_load_count1); 129 /* enable timer */ 130 writel(1, &priv->timer->timer_ctrl_reg); 131 132 return 0; 133 } 134 135 static int rockchip_timer_probe(struct udevice *dev) 136 { 137 #if CONFIG_IS_ENABLED(OF_PLATDATA) 138 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); 139 struct rockchip_timer_priv *priv = dev_get_priv(dev); 140 struct rockchip_timer_plat *plat = dev_get_platdata(dev); 141 142 priv->timer = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); 143 uc_priv->clock_rate = plat->dtd.clock_frequency; 144 #endif 145 146 return rockchip_timer_start(dev); 147 } 148 149 static const struct timer_ops rockchip_timer_ops = { 150 .get_count = rockchip_timer_get_count, 151 }; 152 153 static const struct udevice_id rockchip_timer_ids[] = { 154 { .compatible = "rockchip,rk3188-timer" }, 155 { .compatible = "rockchip,rk3288-timer" }, 156 { .compatible = "rockchip,rk3368-timer" }, 157 {} 158 }; 159 160 U_BOOT_DRIVER(rockchip_rk3368_timer) = { 161 .name = "rockchip_rk3368_timer", 162 .id = UCLASS_TIMER, 163 .of_match = rockchip_timer_ids, 164 .probe = rockchip_timer_probe, 165 .ops = &rockchip_timer_ops, 166 .flags = DM_FLAG_PRE_RELOC, 167 .priv_auto_alloc_size = sizeof(struct rockchip_timer_priv), 168 #if CONFIG_IS_ENABLED(OF_PLATDATA) 169 .platdata_auto_alloc_size = sizeof(struct rockchip_timer_plat), 170 #endif 171 .ofdata_to_platdata = rockchip_clk_ofdata_to_platdata, 172 }; 173