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-frac.c (4881B)


      1/*
      2 * mmp factor clock operation source file
      3 *
      4 * Copyright (C) 2012 Marvell
      5 * Chao Xie <xiechao.mail@gmail.com>
      6 *
      7 * This file is licensed under the terms of the GNU General Public
      8 * License version 2. This program is licensed "as is" without any
      9 * warranty of any kind, whether express or implied.
     10 */
     11
     12#include <linux/clk-provider.h>
     13#include <linux/slab.h>
     14#include <linux/io.h>
     15#include <linux/err.h>
     16
     17#include "clk.h"
     18/*
     19 * It is M/N clock
     20 *
     21 * Fout from synthesizer can be given from two equations:
     22 * numerator/denominator = Fin / (Fout * factor)
     23 */
     24
     25#define to_clk_factor(hw) container_of(hw, struct mmp_clk_factor, hw)
     26
     27static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
     28		unsigned long *prate)
     29{
     30	struct mmp_clk_factor *factor = to_clk_factor(hw);
     31	u64 rate = 0, prev_rate;
     32	int i;
     33
     34	for (i = 0; i < factor->ftbl_cnt; i++) {
     35		prev_rate = rate;
     36		rate = *prate;
     37		rate *= factor->ftbl[i].den;
     38		do_div(rate, factor->ftbl[i].num * factor->masks->factor);
     39
     40		if (rate > drate)
     41			break;
     42	}
     43	if ((i == 0) || (i == factor->ftbl_cnt)) {
     44		return rate;
     45	} else {
     46		if ((drate - prev_rate) > (rate - drate))
     47			return rate;
     48		else
     49			return prev_rate;
     50	}
     51}
     52
     53static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
     54		unsigned long parent_rate)
     55{
     56	struct mmp_clk_factor *factor = to_clk_factor(hw);
     57	struct mmp_clk_factor_masks *masks = factor->masks;
     58	unsigned int val, num, den;
     59	u64 rate;
     60
     61	val = readl_relaxed(factor->base);
     62
     63	/* calculate numerator */
     64	num = (val >> masks->num_shift) & masks->num_mask;
     65
     66	/* calculate denominator */
     67	den = (val >> masks->den_shift) & masks->den_mask;
     68
     69	if (!den)
     70		return 0;
     71
     72	rate = parent_rate;
     73	rate *= den;
     74	do_div(rate, num * factor->masks->factor);
     75
     76	return rate;
     77}
     78
     79/* Configures new clock rate*/
     80static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
     81				unsigned long prate)
     82{
     83	struct mmp_clk_factor *factor = to_clk_factor(hw);
     84	struct mmp_clk_factor_masks *masks = factor->masks;
     85	int i;
     86	unsigned long val;
     87	unsigned long flags = 0;
     88	u64 rate = 0;
     89
     90	for (i = 0; i < factor->ftbl_cnt; i++) {
     91		rate = prate;
     92		rate *= factor->ftbl[i].den;
     93		do_div(rate, factor->ftbl[i].num * factor->masks->factor);
     94
     95		if (rate > drate)
     96			break;
     97	}
     98	if (i > 0)
     99		i--;
    100
    101	if (factor->lock)
    102		spin_lock_irqsave(factor->lock, flags);
    103
    104	val = readl_relaxed(factor->base);
    105
    106	val &= ~(masks->num_mask << masks->num_shift);
    107	val |= (factor->ftbl[i].num & masks->num_mask) << masks->num_shift;
    108
    109	val &= ~(masks->den_mask << masks->den_shift);
    110	val |= (factor->ftbl[i].den & masks->den_mask) << masks->den_shift;
    111
    112	writel_relaxed(val, factor->base);
    113
    114	if (factor->lock)
    115		spin_unlock_irqrestore(factor->lock, flags);
    116
    117	return 0;
    118}
    119
    120static int clk_factor_init(struct clk_hw *hw)
    121{
    122	struct mmp_clk_factor *factor = to_clk_factor(hw);
    123	struct mmp_clk_factor_masks *masks = factor->masks;
    124	u32 val, num, den;
    125	int i;
    126	unsigned long flags = 0;
    127
    128	if (factor->lock)
    129		spin_lock_irqsave(factor->lock, flags);
    130
    131	val = readl(factor->base);
    132
    133	/* calculate numerator */
    134	num = (val >> masks->num_shift) & masks->num_mask;
    135
    136	/* calculate denominator */
    137	den = (val >> masks->den_shift) & masks->den_mask;
    138
    139	for (i = 0; i < factor->ftbl_cnt; i++)
    140		if (den == factor->ftbl[i].den && num == factor->ftbl[i].num)
    141			break;
    142
    143	if (i >= factor->ftbl_cnt) {
    144		val &= ~(masks->num_mask << masks->num_shift);
    145		val |= (factor->ftbl[0].num & masks->num_mask) <<
    146			masks->num_shift;
    147
    148		val &= ~(masks->den_mask << masks->den_shift);
    149		val |= (factor->ftbl[0].den & masks->den_mask) <<
    150			masks->den_shift;
    151	}
    152
    153	if (!(val & masks->enable_mask) || i >= factor->ftbl_cnt) {
    154		val |= masks->enable_mask;
    155		writel(val, factor->base);
    156	}
    157
    158	if (factor->lock)
    159		spin_unlock_irqrestore(factor->lock, flags);
    160
    161	return 0;
    162}
    163
    164static const struct clk_ops clk_factor_ops = {
    165	.recalc_rate = clk_factor_recalc_rate,
    166	.round_rate = clk_factor_round_rate,
    167	.set_rate = clk_factor_set_rate,
    168	.init = clk_factor_init,
    169};
    170
    171struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
    172		unsigned long flags, void __iomem *base,
    173		struct mmp_clk_factor_masks *masks,
    174		struct mmp_clk_factor_tbl *ftbl,
    175		unsigned int ftbl_cnt, spinlock_t *lock)
    176{
    177	struct mmp_clk_factor *factor;
    178	struct clk_init_data init;
    179	struct clk *clk;
    180
    181	if (!masks) {
    182		pr_err("%s: must pass a clk_factor_mask\n", __func__);
    183		return ERR_PTR(-EINVAL);
    184	}
    185
    186	factor = kzalloc(sizeof(*factor), GFP_KERNEL);
    187	if (!factor)
    188		return ERR_PTR(-ENOMEM);
    189
    190	/* struct clk_aux assignments */
    191	factor->base = base;
    192	factor->masks = masks;
    193	factor->ftbl = ftbl;
    194	factor->ftbl_cnt = ftbl_cnt;
    195	factor->hw.init = &init;
    196	factor->lock = lock;
    197
    198	init.name = name;
    199	init.ops = &clk_factor_ops;
    200	init.flags = flags;
    201	init.parent_names = &parent_name;
    202	init.num_parents = 1;
    203
    204	clk = clk_register(NULL, &factor->hw);
    205	if (IS_ERR_OR_NULL(clk))
    206		kfree(factor);
    207
    208	return clk;
    209}