15184f4bfSNick Hawkins // SPDX-License-Identifier: GPL-2.0 25184f4bfSNick Hawkins /* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */ 35184f4bfSNick Hawkins 45184f4bfSNick Hawkins #include <linux/clk.h> 55184f4bfSNick Hawkins #include <linux/clockchips.h> 65184f4bfSNick Hawkins #include <linux/clocksource.h> 75184f4bfSNick Hawkins #include <linux/interrupt.h> 85184f4bfSNick Hawkins #include <linux/of_address.h> 95184f4bfSNick Hawkins #include <linux/of_irq.h> 105184f4bfSNick Hawkins #include <linux/of_platform.h> 11*6303d069SRob Herring #include <linux/platform_device.h> 125184f4bfSNick Hawkins #include <linux/sched_clock.h> 135184f4bfSNick Hawkins 145184f4bfSNick Hawkins #define TIMER0_FREQ 1000000 155184f4bfSNick Hawkins #define GXP_TIMER_CNT_OFS 0x00 165184f4bfSNick Hawkins #define GXP_TIMESTAMP_OFS 0x08 175184f4bfSNick Hawkins #define GXP_TIMER_CTRL_OFS 0x14 185184f4bfSNick Hawkins 195184f4bfSNick Hawkins /* TCS Stands for Timer Control/Status: these are masks to be used in */ 205184f4bfSNick Hawkins /* the Timer Count Registers */ 215184f4bfSNick Hawkins #define MASK_TCS_ENABLE 0x01 225184f4bfSNick Hawkins #define MASK_TCS_PERIOD 0x02 235184f4bfSNick Hawkins #define MASK_TCS_RELOAD 0x04 245184f4bfSNick Hawkins #define MASK_TCS_TC 0x80 255184f4bfSNick Hawkins 265184f4bfSNick Hawkins struct gxp_timer { 275184f4bfSNick Hawkins void __iomem *counter; 285184f4bfSNick Hawkins void __iomem *control; 295184f4bfSNick Hawkins struct clock_event_device evt; 305184f4bfSNick Hawkins }; 315184f4bfSNick Hawkins 325184f4bfSNick Hawkins static struct gxp_timer *gxp_timer; 335184f4bfSNick Hawkins 345184f4bfSNick Hawkins static void __iomem *system_clock __ro_after_init; 355184f4bfSNick Hawkins 365184f4bfSNick Hawkins static inline struct gxp_timer *to_gxp_timer(struct clock_event_device *evt_dev) 375184f4bfSNick Hawkins { 385184f4bfSNick Hawkins return container_of(evt_dev, struct gxp_timer, evt); 395184f4bfSNick Hawkins } 405184f4bfSNick Hawkins 415184f4bfSNick Hawkins static u64 notrace gxp_sched_read(void) 425184f4bfSNick Hawkins { 435184f4bfSNick Hawkins return readl_relaxed(system_clock); 445184f4bfSNick Hawkins } 455184f4bfSNick Hawkins 465184f4bfSNick Hawkins static int gxp_time_set_next_event(unsigned long event, struct clock_event_device *evt_dev) 475184f4bfSNick Hawkins { 485184f4bfSNick Hawkins struct gxp_timer *timer = to_gxp_timer(evt_dev); 495184f4bfSNick Hawkins 505184f4bfSNick Hawkins /* Stop counting and disable interrupt before updating */ 515184f4bfSNick Hawkins writeb_relaxed(MASK_TCS_TC, timer->control); 525184f4bfSNick Hawkins writel_relaxed(event, timer->counter); 535184f4bfSNick Hawkins writeb_relaxed(MASK_TCS_TC | MASK_TCS_ENABLE, timer->control); 545184f4bfSNick Hawkins 555184f4bfSNick Hawkins return 0; 565184f4bfSNick Hawkins } 575184f4bfSNick Hawkins 585184f4bfSNick Hawkins static irqreturn_t gxp_timer_interrupt(int irq, void *dev_id) 595184f4bfSNick Hawkins { 605184f4bfSNick Hawkins struct gxp_timer *timer = (struct gxp_timer *)dev_id; 615184f4bfSNick Hawkins 625184f4bfSNick Hawkins if (!(readb_relaxed(timer->control) & MASK_TCS_TC)) 635184f4bfSNick Hawkins return IRQ_NONE; 645184f4bfSNick Hawkins 655184f4bfSNick Hawkins writeb_relaxed(MASK_TCS_TC, timer->control); 665184f4bfSNick Hawkins 675184f4bfSNick Hawkins timer->evt.event_handler(&timer->evt); 685184f4bfSNick Hawkins 695184f4bfSNick Hawkins return IRQ_HANDLED; 705184f4bfSNick Hawkins } 715184f4bfSNick Hawkins 725184f4bfSNick Hawkins static int __init gxp_timer_init(struct device_node *node) 735184f4bfSNick Hawkins { 745184f4bfSNick Hawkins void __iomem *base; 755184f4bfSNick Hawkins struct clk *clk; 765184f4bfSNick Hawkins u32 freq; 775184f4bfSNick Hawkins int ret, irq; 785184f4bfSNick Hawkins 795184f4bfSNick Hawkins gxp_timer = kzalloc(sizeof(*gxp_timer), GFP_KERNEL); 805184f4bfSNick Hawkins if (!gxp_timer) { 815184f4bfSNick Hawkins ret = -ENOMEM; 825184f4bfSNick Hawkins pr_err("Can't allocate gxp_timer"); 835184f4bfSNick Hawkins return ret; 845184f4bfSNick Hawkins } 855184f4bfSNick Hawkins 865184f4bfSNick Hawkins clk = of_clk_get(node, 0); 875184f4bfSNick Hawkins if (IS_ERR(clk)) { 885184f4bfSNick Hawkins ret = (int)PTR_ERR(clk); 895184f4bfSNick Hawkins pr_err("%pOFn clock not found: %d\n", node, ret); 905184f4bfSNick Hawkins goto err_free; 915184f4bfSNick Hawkins } 925184f4bfSNick Hawkins 935184f4bfSNick Hawkins ret = clk_prepare_enable(clk); 945184f4bfSNick Hawkins if (ret) { 955184f4bfSNick Hawkins pr_err("%pOFn clock enable failed: %d\n", node, ret); 965184f4bfSNick Hawkins goto err_clk_enable; 975184f4bfSNick Hawkins } 985184f4bfSNick Hawkins 995184f4bfSNick Hawkins base = of_iomap(node, 0); 1005184f4bfSNick Hawkins if (!base) { 1015184f4bfSNick Hawkins ret = -ENXIO; 1025184f4bfSNick Hawkins pr_err("Can't map timer base registers"); 1035184f4bfSNick Hawkins goto err_iomap; 1045184f4bfSNick Hawkins } 1055184f4bfSNick Hawkins 1065184f4bfSNick Hawkins /* Set the offsets to the clock register and timer registers */ 1075184f4bfSNick Hawkins gxp_timer->counter = base + GXP_TIMER_CNT_OFS; 1085184f4bfSNick Hawkins gxp_timer->control = base + GXP_TIMER_CTRL_OFS; 1095184f4bfSNick Hawkins system_clock = base + GXP_TIMESTAMP_OFS; 1105184f4bfSNick Hawkins 1115184f4bfSNick Hawkins gxp_timer->evt.name = node->name; 1125184f4bfSNick Hawkins gxp_timer->evt.rating = 300; 1135184f4bfSNick Hawkins gxp_timer->evt.features = CLOCK_EVT_FEAT_ONESHOT; 1145184f4bfSNick Hawkins gxp_timer->evt.set_next_event = gxp_time_set_next_event; 1155184f4bfSNick Hawkins gxp_timer->evt.cpumask = cpumask_of(0); 1165184f4bfSNick Hawkins 1175184f4bfSNick Hawkins irq = irq_of_parse_and_map(node, 0); 1185184f4bfSNick Hawkins if (irq <= 0) { 1195184f4bfSNick Hawkins ret = -EINVAL; 1205184f4bfSNick Hawkins pr_err("GXP Timer Can't parse IRQ %d", irq); 1215184f4bfSNick Hawkins goto err_exit; 1225184f4bfSNick Hawkins } 1235184f4bfSNick Hawkins 1245184f4bfSNick Hawkins freq = clk_get_rate(clk); 1255184f4bfSNick Hawkins 1265184f4bfSNick Hawkins ret = clocksource_mmio_init(system_clock, node->name, freq, 1275184f4bfSNick Hawkins 300, 32, clocksource_mmio_readl_up); 1285184f4bfSNick Hawkins if (ret) { 1295184f4bfSNick Hawkins pr_err("%pOFn init clocksource failed: %d", node, ret); 1305184f4bfSNick Hawkins goto err_exit; 1315184f4bfSNick Hawkins } 1325184f4bfSNick Hawkins 1335184f4bfSNick Hawkins sched_clock_register(gxp_sched_read, 32, freq); 1345184f4bfSNick Hawkins 1355184f4bfSNick Hawkins irq = irq_of_parse_and_map(node, 0); 1365184f4bfSNick Hawkins if (irq <= 0) { 1375184f4bfSNick Hawkins ret = -EINVAL; 1385184f4bfSNick Hawkins pr_err("%pOFn Can't parse IRQ %d", node, irq); 1395184f4bfSNick Hawkins goto err_exit; 1405184f4bfSNick Hawkins } 1415184f4bfSNick Hawkins 1425184f4bfSNick Hawkins clockevents_config_and_register(&gxp_timer->evt, TIMER0_FREQ, 1435184f4bfSNick Hawkins 0xf, 0xffffffff); 1445184f4bfSNick Hawkins 1455184f4bfSNick Hawkins ret = request_irq(irq, gxp_timer_interrupt, IRQF_TIMER | IRQF_SHARED, 1465184f4bfSNick Hawkins node->name, gxp_timer); 1475184f4bfSNick Hawkins if (ret) { 1485184f4bfSNick Hawkins pr_err("%pOFn request_irq() failed: %d", node, ret); 1495184f4bfSNick Hawkins goto err_exit; 1505184f4bfSNick Hawkins } 1515184f4bfSNick Hawkins 1525184f4bfSNick Hawkins pr_debug("gxp: system timer (irq = %d)\n", irq); 1535184f4bfSNick Hawkins return 0; 1545184f4bfSNick Hawkins 1555184f4bfSNick Hawkins err_exit: 1565184f4bfSNick Hawkins iounmap(base); 1575184f4bfSNick Hawkins err_iomap: 1585184f4bfSNick Hawkins clk_disable_unprepare(clk); 1595184f4bfSNick Hawkins err_clk_enable: 1605184f4bfSNick Hawkins clk_put(clk); 1615184f4bfSNick Hawkins err_free: 1625184f4bfSNick Hawkins kfree(gxp_timer); 1635184f4bfSNick Hawkins return ret; 1645184f4bfSNick Hawkins } 1655184f4bfSNick Hawkins 1665184f4bfSNick Hawkins /* 1675184f4bfSNick Hawkins * This probe gets called after the timer is already up and running. This will create 1685184f4bfSNick Hawkins * the watchdog device as a child since the registers are shared. 1695184f4bfSNick Hawkins */ 1705184f4bfSNick Hawkins 1715184f4bfSNick Hawkins static int gxp_timer_probe(struct platform_device *pdev) 1725184f4bfSNick Hawkins { 1735184f4bfSNick Hawkins struct platform_device *gxp_watchdog_device; 1745184f4bfSNick Hawkins struct device *dev = &pdev->dev; 1750e2c8e6dSLin Yujun int ret; 1765184f4bfSNick Hawkins 1775184f4bfSNick Hawkins if (!gxp_timer) { 1785184f4bfSNick Hawkins pr_err("Gxp Timer not initialized, cannot create watchdog"); 1795184f4bfSNick Hawkins return -ENOMEM; 1805184f4bfSNick Hawkins } 1815184f4bfSNick Hawkins 1825184f4bfSNick Hawkins gxp_watchdog_device = platform_device_alloc("gxp-wdt", -1); 1835184f4bfSNick Hawkins if (!gxp_watchdog_device) { 1845184f4bfSNick Hawkins pr_err("Timer failed to allocate gxp-wdt"); 1855184f4bfSNick Hawkins return -ENOMEM; 1865184f4bfSNick Hawkins } 1875184f4bfSNick Hawkins 1885184f4bfSNick Hawkins /* Pass the base address (counter) as platform data and nothing else */ 1895184f4bfSNick Hawkins gxp_watchdog_device->dev.platform_data = gxp_timer->counter; 1905184f4bfSNick Hawkins gxp_watchdog_device->dev.parent = dev; 1915184f4bfSNick Hawkins 1920e2c8e6dSLin Yujun ret = platform_device_add(gxp_watchdog_device); 1930e2c8e6dSLin Yujun if (ret) 1940e2c8e6dSLin Yujun platform_device_put(gxp_watchdog_device); 1950e2c8e6dSLin Yujun 1960e2c8e6dSLin Yujun return ret; 1975184f4bfSNick Hawkins } 1985184f4bfSNick Hawkins 1995184f4bfSNick Hawkins static const struct of_device_id gxp_timer_of_match[] = { 2005184f4bfSNick Hawkins { .compatible = "hpe,gxp-timer", }, 2015184f4bfSNick Hawkins {}, 2025184f4bfSNick Hawkins }; 2035184f4bfSNick Hawkins 2045184f4bfSNick Hawkins static struct platform_driver gxp_timer_driver = { 2055184f4bfSNick Hawkins .probe = gxp_timer_probe, 2065184f4bfSNick Hawkins .driver = { 2075184f4bfSNick Hawkins .name = "gxp-timer", 2085184f4bfSNick Hawkins .of_match_table = gxp_timer_of_match, 2095184f4bfSNick Hawkins .suppress_bind_attrs = true, 2105184f4bfSNick Hawkins }, 2115184f4bfSNick Hawkins }; 2125184f4bfSNick Hawkins 2135184f4bfSNick Hawkins builtin_platform_driver(gxp_timer_driver); 2145184f4bfSNick Hawkins 2155184f4bfSNick Hawkins TIMER_OF_DECLARE(gxp, "hpe,gxp-timer", gxp_timer_init); 216