"Das U-Boot" Source Tree
at master 149 lines 3.5 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2#include <asm/io.h> 3#include <config.h> 4#include <div64.h> 5#include <dm/device.h> 6#include <dm/fdtaddr.h> 7#include <timer.h> 8 9#define TIMER_CTRL 0x00 10#define TIMER0_EN BIT(0) 11#define TIMER0_RELOAD_EN BIT(1) 12#define TIMER0_RELOAD 0x10 13#define TIMER0_VAL 0x14 14 15enum input_clock_type { 16 INPUT_CLOCK_NON_FIXED, 17 INPUT_CLOCK_25MHZ, /* input clock rate is fixed to 25MHz */ 18}; 19 20struct orion_timer_priv { 21 void *base; 22}; 23 24#define MVEBU_TIMER_FIXED_RATE_25MHZ 25000000 25 26static bool early_init_done(void *base) 27{ 28 if ((readl(base + TIMER_CTRL) & TIMER0_EN) && 29 (readl(base + TIMER0_RELOAD) == ~0)) 30 return true; 31 return false; 32} 33 34/* Common functions for early (boot) and DM based timer */ 35static void orion_timer_init(void *base, enum input_clock_type type) 36{ 37 /* Only init the timer once */ 38 if (early_init_done(base)) 39 return; 40 41 writel(~0, base + TIMER0_VAL); 42 writel(~0, base + TIMER0_RELOAD); 43 44 if (type == INPUT_CLOCK_25MHZ) { 45 /* 46 * On Armada XP / 38x ..., the 25MHz clock source needs to 47 * be enabled 48 */ 49 setbits_le32(base + TIMER_CTRL, BIT(11)); 50 } 51 52 /* enable timer */ 53 setbits_le32(base + TIMER_CTRL, TIMER0_EN | TIMER0_RELOAD_EN); 54} 55 56static uint64_t orion_timer_get_count(void *base) 57{ 58 return timer_conv_64(~readl(base + TIMER0_VAL)); 59} 60 61/* Early (e.g. bootstage etc) timer functions */ 62static void notrace timer_early_init(void) 63{ 64 if (IS_ENABLED(CONFIG_ARCH_MVEBU)) 65 orion_timer_init((void *)MVEBU_TIMER_BASE, INPUT_CLOCK_25MHZ); 66 else 67 orion_timer_init((void *)MVEBU_TIMER_BASE, INPUT_CLOCK_NON_FIXED); 68} 69 70/** 71 * timer_early_get_rate() - Get the timer rate before driver model 72 */ 73unsigned long notrace timer_early_get_rate(void) 74{ 75 timer_early_init(); 76 77 if (IS_ENABLED(CONFIG_ARCH_MVEBU)) 78 return MVEBU_TIMER_FIXED_RATE_25MHZ; 79 else 80 return CFG_SYS_TCLK; 81} 82 83/** 84 * timer_early_get_count() - Get the timer count before driver model 85 * 86 */ 87u64 notrace timer_early_get_count(void) 88{ 89 timer_early_init(); 90 91 return orion_timer_get_count((void *)MVEBU_TIMER_BASE); 92} 93 94ulong timer_get_boot_us(void) 95{ 96 u64 ticks; 97 98 ticks = timer_early_get_count(); 99 return lldiv(ticks * 1000, timer_early_get_rate()); 100} 101 102/* DM timer functions */ 103static uint64_t dm_orion_timer_get_count(struct udevice *dev) 104{ 105 struct orion_timer_priv *priv = dev_get_priv(dev); 106 107 return orion_timer_get_count(priv->base); 108} 109 110static int orion_timer_probe(struct udevice *dev) 111{ 112 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); 113 enum input_clock_type type = dev_get_driver_data(dev); 114 struct orion_timer_priv *priv = dev_get_priv(dev); 115 116 priv->base = devfdt_remap_addr_index(dev, 0); 117 if (!priv->base) { 118 debug("unable to map registers\n"); 119 return -ENOMEM; 120 } 121 122 if (type == INPUT_CLOCK_25MHZ) 123 uc_priv->clock_rate = MVEBU_TIMER_FIXED_RATE_25MHZ; 124 else 125 uc_priv->clock_rate = CFG_SYS_TCLK; 126 orion_timer_init(priv->base, type); 127 128 return 0; 129} 130 131static const struct timer_ops orion_timer_ops = { 132 .get_count = dm_orion_timer_get_count, 133}; 134 135static const struct udevice_id orion_timer_ids[] = { 136 { .compatible = "marvell,orion-timer", .data = INPUT_CLOCK_NON_FIXED }, 137 { .compatible = "marvell,armada-370-timer", .data = INPUT_CLOCK_25MHZ }, 138 { .compatible = "marvell,armada-xp-timer", .data = INPUT_CLOCK_25MHZ }, 139 {} 140}; 141 142U_BOOT_DRIVER(orion_timer) = { 143 .name = "orion_timer", 144 .id = UCLASS_TIMER, 145 .of_match = orion_timer_ids, 146 .probe = orion_timer_probe, 147 .ops = &orion_timer_ops, 148 .priv_auto = sizeof(struct orion_timer_priv), 149};