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

clk-gpt-synth.c (3527B)


      1/*
      2 * Copyright (C) 2012 ST Microelectronics
      3 * Viresh Kumar <vireshk@kernel.org>
      4 *
      5 * This file is licensed under the terms of the GNU General Public
      6 * License version 2. This program is licensed "as is" without any
      7 * warranty of any kind, whether express or implied.
      8 *
      9 * General Purpose Timer Synthesizer clock implementation
     10 */
     11
     12#define pr_fmt(fmt) "clk-gpt-synth: " fmt
     13
     14#include <linux/clk-provider.h>
     15#include <linux/slab.h>
     16#include <linux/io.h>
     17#include <linux/err.h>
     18#include "clk.h"
     19
     20#define GPT_MSCALE_MASK		0xFFF
     21#define GPT_NSCALE_SHIFT	12
     22#define GPT_NSCALE_MASK		0xF
     23
     24/*
     25 * DOC: General Purpose Timer Synthesizer clock
     26 *
     27 * Calculates gpt synth clk rate for different values of mscale and nscale
     28 *
     29 * Fout= Fin/((2 ^ (N+1)) * (M+1))
     30 */
     31
     32#define to_clk_gpt(_hw) container_of(_hw, struct clk_gpt, hw)
     33
     34static unsigned long gpt_calc_rate(struct clk_hw *hw, unsigned long prate,
     35		int index)
     36{
     37	struct clk_gpt *gpt = to_clk_gpt(hw);
     38	struct gpt_rate_tbl *rtbl = gpt->rtbl;
     39
     40	prate /= ((1 << (rtbl[index].nscale + 1)) * (rtbl[index].mscale + 1));
     41
     42	return prate;
     43}
     44
     45static long clk_gpt_round_rate(struct clk_hw *hw, unsigned long drate,
     46		unsigned long *prate)
     47{
     48	struct clk_gpt *gpt = to_clk_gpt(hw);
     49	int unused;
     50
     51	return clk_round_rate_index(hw, drate, *prate, gpt_calc_rate,
     52			gpt->rtbl_cnt, &unused);
     53}
     54
     55static unsigned long clk_gpt_recalc_rate(struct clk_hw *hw,
     56		unsigned long parent_rate)
     57{
     58	struct clk_gpt *gpt = to_clk_gpt(hw);
     59	unsigned long flags = 0;
     60	unsigned int div = 1, val;
     61
     62	if (gpt->lock)
     63		spin_lock_irqsave(gpt->lock, flags);
     64
     65	val = readl_relaxed(gpt->reg);
     66
     67	if (gpt->lock)
     68		spin_unlock_irqrestore(gpt->lock, flags);
     69
     70	div += val & GPT_MSCALE_MASK;
     71	div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1);
     72
     73	if (!div)
     74		return 0;
     75
     76	return parent_rate / div;
     77}
     78
     79/* Configures new clock rate of gpt */
     80static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate,
     81				unsigned long prate)
     82{
     83	struct clk_gpt *gpt = to_clk_gpt(hw);
     84	struct gpt_rate_tbl *rtbl = gpt->rtbl;
     85	unsigned long flags = 0, val;
     86	int i;
     87
     88	clk_round_rate_index(hw, drate, prate, gpt_calc_rate, gpt->rtbl_cnt,
     89			&i);
     90
     91	if (gpt->lock)
     92		spin_lock_irqsave(gpt->lock, flags);
     93
     94	val = readl(gpt->reg) & ~GPT_MSCALE_MASK;
     95	val &= ~(GPT_NSCALE_MASK << GPT_NSCALE_SHIFT);
     96
     97	val |= rtbl[i].mscale & GPT_MSCALE_MASK;
     98	val |= (rtbl[i].nscale & GPT_NSCALE_MASK) << GPT_NSCALE_SHIFT;
     99
    100	writel_relaxed(val, gpt->reg);
    101
    102	if (gpt->lock)
    103		spin_unlock_irqrestore(gpt->lock, flags);
    104
    105	return 0;
    106}
    107
    108static const struct clk_ops clk_gpt_ops = {
    109	.recalc_rate = clk_gpt_recalc_rate,
    110	.round_rate = clk_gpt_round_rate,
    111	.set_rate = clk_gpt_set_rate,
    112};
    113
    114struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned
    115		long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8
    116		rtbl_cnt, spinlock_t *lock)
    117{
    118	struct clk_init_data init;
    119	struct clk_gpt *gpt;
    120	struct clk *clk;
    121
    122	if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) {
    123		pr_err("Invalid arguments passed\n");
    124		return ERR_PTR(-EINVAL);
    125	}
    126
    127	gpt = kzalloc(sizeof(*gpt), GFP_KERNEL);
    128	if (!gpt)
    129		return ERR_PTR(-ENOMEM);
    130
    131	/* struct clk_gpt assignments */
    132	gpt->reg = reg;
    133	gpt->rtbl = rtbl;
    134	gpt->rtbl_cnt = rtbl_cnt;
    135	gpt->lock = lock;
    136	gpt->hw.init = &init;
    137
    138	init.name = name;
    139	init.ops = &clk_gpt_ops;
    140	init.flags = flags;
    141	init.parent_names = &parent_name;
    142	init.num_parents = 1;
    143
    144	clk = clk_register(NULL, &gpt->hw);
    145	if (!IS_ERR_OR_NULL(clk))
    146		return clk;
    147
    148	pr_err("clk register failed\n");
    149	kfree(gpt);
    150
    151	return NULL;
    152}