1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * 64-bit Periodic Interval Timer driver 4 * 5 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries 6 * 7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com> 8 */ 9 10#include <common.h> 11#include <clk.h> 12#include <dm.h> 13#include <timer.h> 14#include <asm/io.h> 15 16#define MCHP_PIT64B_CR 0x00 /* Control Register */ 17#define MCHP_PIT64B_CR_START BIT(0) 18#define MCHP_PIT64B_CR_SWRST BIT(8) 19#define MCHP_PIT64B_MR 0x04 /* Mode Register */ 20#define MCHP_PIT64B_MR_CONT BIT(0) 21#define MCHP_PIT64B_LSB_PR 0x08 /* LSB Period Register */ 22#define MCHP_PIT64B_MSB_PR 0x0C /* MSB Period Register */ 23#define MCHP_PIT64B_TLSBR 0x20 /* Timer LSB Register */ 24#define MCHP_PIT64B_TMSBR 0x24 /* Timer MSB Register */ 25 26struct mchp_pit64b_priv { 27 void __iomem *base; 28}; 29 30static u64 mchp_pit64b_get_count(struct udevice *dev) 31{ 32 struct mchp_pit64b_priv *priv = dev_get_priv(dev); 33 34 u32 lsb = readl(priv->base + MCHP_PIT64B_TLSBR); 35 u32 msb = readl(priv->base + MCHP_PIT64B_TMSBR); 36 37 return ((u64)msb << 32) | lsb; 38} 39 40static int mchp_pit64b_probe(struct udevice *dev) 41{ 42 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); 43 struct mchp_pit64b_priv *priv = dev_get_priv(dev); 44 struct clk clk; 45 ulong rate; 46 int ret; 47 48 priv->base = dev_read_addr_ptr(dev); 49 if (IS_ERR(priv->base)) 50 return PTR_ERR(priv->base); 51 52 ret = clk_get_by_index(dev, 0, &clk); 53 if (ret) 54 return ret; 55 56 ret = clk_enable(&clk); 57 if (ret) 58 return ret; 59 60 rate = clk_get_rate(&clk); 61 if (!rate) { 62 clk_disable(&clk); 63 return -ENOTSUPP; 64 } 65 66 /* Reset the timer in case it was used by previous bootloaders. */ 67 writel(MCHP_PIT64B_CR_SWRST, priv->base + MCHP_PIT64B_CR); 68 69 /* 70 * Use highest prescaller (for a peripheral clock running at 200MHz 71 * this will lead to the timer running at 12.5MHz) and continuous mode. 72 */ 73 writel((15 << 8) | MCHP_PIT64B_MR_CONT, priv->base + MCHP_PIT64B_MR); 74 uc_priv->clock_rate = rate / 16; 75 76 /* 77 * Simulate free running counter by setting max values to period 78 * registers. 79 */ 80 writel(~0UL, priv->base + MCHP_PIT64B_MSB_PR); 81 writel(~0UL, priv->base + MCHP_PIT64B_LSB_PR); 82 83 /* Start the timer. */ 84 writel(MCHP_PIT64B_CR_START, priv->base + MCHP_PIT64B_CR); 85 86 return 0; 87} 88 89static const struct timer_ops mchp_pit64b_ops = { 90 .get_count = mchp_pit64b_get_count, 91}; 92 93static const struct udevice_id mchp_pit64b_ids[] = { 94 { .compatible = "microchip,sam9x60-pit64b", }, 95 { .compatible = "microchip,sama7g5-pit64b", }, 96 { } 97}; 98 99U_BOOT_DRIVER(mchp_pit64b) = { 100 .name = "mchp-pit64b", 101 .id = UCLASS_TIMER, 102 .of_match = mchp_pit64b_ids, 103 .priv_auto = sizeof(struct mchp_pit64b_priv), 104 .probe = mchp_pit64b_probe, 105 .ops = &mchp_pit64b_ops, 106 .flags = DM_FLAG_PRE_RELOC, 107}; 108