1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018 Xilinx, Inc. (Michal Simek) 4 */ 5 6#include <common.h> 7#include <bootstage.h> 8#include <dm.h> 9#include <errno.h> 10#include <init.h> 11#include <timer.h> 12#include <asm/global_data.h> 13#include <asm/io.h> 14#include <linux/bitops.h> 15#include <linux/err.h> 16 17#define CNT_CNTRL_RESET BIT(4) 18 19struct cadence_ttc_regs { 20 u32 clk_cntrl1; /* 0x0 - Clock Control 1 */ 21 u32 clk_cntrl2; /* 0x4 - Clock Control 2 */ 22 u32 clk_cntrl3; /* 0x8 - Clock Control 3 */ 23 u32 counter_cntrl1; /* 0xC - Counter Control 1 */ 24 u32 counter_cntrl2; /* 0x10 - Counter Control 2 */ 25 u32 counter_cntrl3; /* 0x14 - Counter Control 3 */ 26 u32 counter_val1; /* 0x18 - Counter Control 1 */ 27 u32 counter_val2; /* 0x1C - Counter Control 2 */ 28 u32 counter_val3; /* 0x20 - Counter Control 3 */ 29 u32 reserved[15]; 30 u32 interrupt_enable1; /* 0x60 - Interrupt Enable 1 */ 31 u32 interrupt_enable2; /* 0x64 - Interrupt Enable 2 */ 32 u32 interrupt_enable3; /* 0x68 - Interrupt Enable 3 */ 33}; 34 35struct cadence_ttc_priv { 36 struct cadence_ttc_regs *regs; 37}; 38 39#if CONFIG_IS_ENABLED(BOOTSTAGE) 40ulong timer_get_boot_us(void) 41{ 42 u64 ticks = 0; 43 u32 rate = 1; 44 u64 us; 45 int ret; 46 47 ret = dm_timer_init(); 48 if (!ret) { 49 /* The timer is available */ 50 rate = timer_get_rate(gd->timer); 51 timer_get_count(gd->timer, &ticks); 52 } else { 53 return 0; 54 } 55 56 us = (ticks * 1000) / rate; 57 return us; 58} 59#endif 60 61static u64 cadence_ttc_get_count(struct udevice *dev) 62{ 63 struct cadence_ttc_priv *priv = dev_get_priv(dev); 64 65 return readl(&priv->regs->counter_val1); 66} 67 68static int cadence_ttc_probe(struct udevice *dev) 69{ 70 struct cadence_ttc_priv *priv = dev_get_priv(dev); 71 72 /* Disable interrupts for sure */ 73 writel(0, &priv->regs->interrupt_enable1); 74 writel(0, &priv->regs->interrupt_enable2); 75 writel(0, &priv->regs->interrupt_enable3); 76 77 /* Make sure that clocks are configured properly without prescaller */ 78 writel(0, &priv->regs->clk_cntrl1); 79 writel(0, &priv->regs->clk_cntrl2); 80 writel(0, &priv->regs->clk_cntrl3); 81 82 /* Reset and enable this counter */ 83 writel(CNT_CNTRL_RESET, &priv->regs->counter_cntrl1); 84 85 return 0; 86} 87 88static int cadence_ttc_of_to_plat(struct udevice *dev) 89{ 90 struct cadence_ttc_priv *priv = dev_get_priv(dev); 91 92 priv->regs = map_physmem(dev_read_addr(dev), 93 sizeof(struct cadence_ttc_regs), MAP_NOCACHE); 94 if (IS_ERR(priv->regs)) 95 return PTR_ERR(priv->regs); 96 97 return 0; 98} 99 100static int cadence_ttc_bind(struct udevice *dev) 101{ 102 const char *cells; 103 104 cells = dev_read_prop(dev, "#pwm-cells", NULL); 105 if (cells) 106 return -ENODEV; 107 108 return 0; 109} 110 111static const struct timer_ops cadence_ttc_ops = { 112 .get_count = cadence_ttc_get_count, 113}; 114 115static const struct udevice_id cadence_ttc_ids[] = { 116 { .compatible = "cdns,ttc" }, 117 {} 118}; 119 120U_BOOT_DRIVER(cadence_ttc) = { 121 .name = "cadence_ttc", 122 .id = UCLASS_TIMER, 123 .of_match = cadence_ttc_ids, 124 .of_to_plat = cadence_ttc_of_to_plat, 125 .priv_auto = sizeof(struct cadence_ttc_priv), 126 .probe = cadence_ttc_probe, 127 .ops = &cadence_ttc_ops, 128 .bind = cadence_ttc_bind, 129}; 130