cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clksrc_st_lpc.c (2873B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Clocksource using the Low Power Timer found in the Low Power Controller (LPC)
      4 *
      5 * Copyright (C) 2015 STMicroelectronics – All Rights Reserved
      6 *
      7 * Author(s): Francesco Virlinzi <francesco.virlinzi@st.com>
      8 *	      Ajit Pal Singh <ajitpal.singh@st.com>
      9 */
     10
     11#include <linux/clk.h>
     12#include <linux/clocksource.h>
     13#include <linux/init.h>
     14#include <linux/of_address.h>
     15#include <linux/sched_clock.h>
     16#include <linux/slab.h>
     17
     18#include <dt-bindings/mfd/st-lpc.h>
     19
     20/* Low Power Timer */
     21#define LPC_LPT_LSB_OFF		0x400
     22#define LPC_LPT_MSB_OFF		0x404
     23#define LPC_LPT_START_OFF	0x408
     24
     25static struct st_clksrc_ddata {
     26	struct clk		*clk;
     27	void __iomem		*base;
     28} ddata;
     29
     30static void __init st_clksrc_reset(void)
     31{
     32	writel_relaxed(0, ddata.base + LPC_LPT_START_OFF);
     33	writel_relaxed(0, ddata.base + LPC_LPT_MSB_OFF);
     34	writel_relaxed(0, ddata.base + LPC_LPT_LSB_OFF);
     35	writel_relaxed(1, ddata.base + LPC_LPT_START_OFF);
     36}
     37
     38static u64 notrace st_clksrc_sched_clock_read(void)
     39{
     40	return (u64)readl_relaxed(ddata.base + LPC_LPT_LSB_OFF);
     41}
     42
     43static int __init st_clksrc_init(void)
     44{
     45	unsigned long rate;
     46	int ret;
     47
     48	st_clksrc_reset();
     49
     50	rate = clk_get_rate(ddata.clk);
     51
     52	sched_clock_register(st_clksrc_sched_clock_read, 32, rate);
     53
     54	ret = clocksource_mmio_init(ddata.base + LPC_LPT_LSB_OFF,
     55				    "clksrc-st-lpc", rate, 300, 32,
     56				    clocksource_mmio_readl_up);
     57	if (ret) {
     58		pr_err("clksrc-st-lpc: Failed to register clocksource\n");
     59		return ret;
     60	}
     61
     62	return 0;
     63}
     64
     65static int __init st_clksrc_setup_clk(struct device_node *np)
     66{
     67	struct clk *clk;
     68
     69	clk = of_clk_get(np, 0);
     70	if (IS_ERR(clk)) {
     71		pr_err("clksrc-st-lpc: Failed to get LPC clock\n");
     72		return PTR_ERR(clk);
     73	}
     74
     75	if (clk_prepare_enable(clk)) {
     76		pr_err("clksrc-st-lpc: Failed to enable LPC clock\n");
     77		return -EINVAL;
     78	}
     79
     80	if (!clk_get_rate(clk)) {
     81		pr_err("clksrc-st-lpc: Failed to get LPC clock rate\n");
     82		clk_disable_unprepare(clk);
     83		return -EINVAL;
     84	}
     85
     86	ddata.clk = clk;
     87
     88	return 0;
     89}
     90
     91static int __init st_clksrc_of_register(struct device_node *np)
     92{
     93	int ret;
     94	uint32_t mode;
     95
     96	ret = of_property_read_u32(np, "st,lpc-mode", &mode);
     97	if (ret) {
     98		pr_err("clksrc-st-lpc: An LPC mode must be provided\n");
     99		return ret;
    100	}
    101
    102	/* LPC can either run as a Clocksource or in RTC or WDT mode */
    103	if (mode != ST_LPC_MODE_CLKSRC)
    104		return 0;
    105
    106	ddata.base = of_iomap(np, 0);
    107	if (!ddata.base) {
    108		pr_err("clksrc-st-lpc: Unable to map iomem\n");
    109		return -ENXIO;
    110	}
    111
    112	ret = st_clksrc_setup_clk(np);
    113	if (ret) {
    114		iounmap(ddata.base);
    115		return ret;
    116	}
    117
    118	ret = st_clksrc_init();
    119	if (ret) {
    120		clk_disable_unprepare(ddata.clk);
    121		clk_put(ddata.clk);
    122		iounmap(ddata.base);
    123		return ret;
    124	}
    125
    126	pr_info("clksrc-st-lpc: clocksource initialised - running @ %luHz\n",
    127		clk_get_rate(ddata.clk));
    128
    129	return ret;
    130}
    131TIMER_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register);