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

ccu_nkm.c (4988B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2016 Maxime Ripard
      4 * Maxime Ripard <maxime.ripard@free-electrons.com>
      5 */
      6
      7#include <linux/clk-provider.h>
      8#include <linux/io.h>
      9
     10#include "ccu_gate.h"
     11#include "ccu_nkm.h"
     12
     13struct _ccu_nkm {
     14	unsigned long	n, min_n, max_n;
     15	unsigned long	k, min_k, max_k;
     16	unsigned long	m, min_m, max_m;
     17};
     18
     19static void ccu_nkm_find_best(unsigned long parent, unsigned long rate,
     20			      struct _ccu_nkm *nkm)
     21{
     22	unsigned long best_rate = 0;
     23	unsigned long best_n = 0, best_k = 0, best_m = 0;
     24	unsigned long _n, _k, _m;
     25
     26	for (_k = nkm->min_k; _k <= nkm->max_k; _k++) {
     27		for (_n = nkm->min_n; _n <= nkm->max_n; _n++) {
     28			for (_m = nkm->min_m; _m <= nkm->max_m; _m++) {
     29				unsigned long tmp_rate;
     30
     31				tmp_rate = parent * _n * _k / _m;
     32
     33				if (tmp_rate > rate)
     34					continue;
     35				if ((rate - tmp_rate) < (rate - best_rate)) {
     36					best_rate = tmp_rate;
     37					best_n = _n;
     38					best_k = _k;
     39					best_m = _m;
     40				}
     41			}
     42		}
     43	}
     44
     45	nkm->n = best_n;
     46	nkm->k = best_k;
     47	nkm->m = best_m;
     48}
     49
     50static void ccu_nkm_disable(struct clk_hw *hw)
     51{
     52	struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
     53
     54	return ccu_gate_helper_disable(&nkm->common, nkm->enable);
     55}
     56
     57static int ccu_nkm_enable(struct clk_hw *hw)
     58{
     59	struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
     60
     61	return ccu_gate_helper_enable(&nkm->common, nkm->enable);
     62}
     63
     64static int ccu_nkm_is_enabled(struct clk_hw *hw)
     65{
     66	struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
     67
     68	return ccu_gate_helper_is_enabled(&nkm->common, nkm->enable);
     69}
     70
     71static unsigned long ccu_nkm_recalc_rate(struct clk_hw *hw,
     72					unsigned long parent_rate)
     73{
     74	struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
     75	unsigned long n, m, k, rate;
     76	u32 reg;
     77
     78	reg = readl(nkm->common.base + nkm->common.reg);
     79
     80	n = reg >> nkm->n.shift;
     81	n &= (1 << nkm->n.width) - 1;
     82	n += nkm->n.offset;
     83	if (!n)
     84		n++;
     85
     86	k = reg >> nkm->k.shift;
     87	k &= (1 << nkm->k.width) - 1;
     88	k += nkm->k.offset;
     89	if (!k)
     90		k++;
     91
     92	m = reg >> nkm->m.shift;
     93	m &= (1 << nkm->m.width) - 1;
     94	m += nkm->m.offset;
     95	if (!m)
     96		m++;
     97
     98	rate = parent_rate * n  * k / m;
     99
    100	if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
    101		rate /= nkm->fixed_post_div;
    102
    103	return rate;
    104}
    105
    106static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
    107					struct clk_hw *hw,
    108					unsigned long *parent_rate,
    109					unsigned long rate,
    110					void *data)
    111{
    112	struct ccu_nkm *nkm = data;
    113	struct _ccu_nkm _nkm;
    114
    115	_nkm.min_n = nkm->n.min ?: 1;
    116	_nkm.max_n = nkm->n.max ?: 1 << nkm->n.width;
    117	_nkm.min_k = nkm->k.min ?: 1;
    118	_nkm.max_k = nkm->k.max ?: 1 << nkm->k.width;
    119	_nkm.min_m = 1;
    120	_nkm.max_m = nkm->m.max ?: 1 << nkm->m.width;
    121
    122	if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
    123		rate *= nkm->fixed_post_div;
    124
    125	ccu_nkm_find_best(*parent_rate, rate, &_nkm);
    126
    127	rate = *parent_rate * _nkm.n * _nkm.k / _nkm.m;
    128
    129	if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
    130		rate /= nkm->fixed_post_div;
    131
    132	return rate;
    133}
    134
    135static int ccu_nkm_determine_rate(struct clk_hw *hw,
    136				  struct clk_rate_request *req)
    137{
    138	struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
    139
    140	return ccu_mux_helper_determine_rate(&nkm->common, &nkm->mux,
    141					     req, ccu_nkm_round_rate, nkm);
    142}
    143
    144static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate,
    145			   unsigned long parent_rate)
    146{
    147	struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
    148	struct _ccu_nkm _nkm;
    149	unsigned long flags;
    150	u32 reg;
    151
    152	if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
    153		rate *= nkm->fixed_post_div;
    154
    155	_nkm.min_n = nkm->n.min ?: 1;
    156	_nkm.max_n = nkm->n.max ?: 1 << nkm->n.width;
    157	_nkm.min_k = nkm->k.min ?: 1;
    158	_nkm.max_k = nkm->k.max ?: 1 << nkm->k.width;
    159	_nkm.min_m = 1;
    160	_nkm.max_m = nkm->m.max ?: 1 << nkm->m.width;
    161
    162	ccu_nkm_find_best(parent_rate, rate, &_nkm);
    163
    164	spin_lock_irqsave(nkm->common.lock, flags);
    165
    166	reg = readl(nkm->common.base + nkm->common.reg);
    167	reg &= ~GENMASK(nkm->n.width + nkm->n.shift - 1, nkm->n.shift);
    168	reg &= ~GENMASK(nkm->k.width + nkm->k.shift - 1, nkm->k.shift);
    169	reg &= ~GENMASK(nkm->m.width + nkm->m.shift - 1, nkm->m.shift);
    170
    171	reg |= (_nkm.n - nkm->n.offset) << nkm->n.shift;
    172	reg |= (_nkm.k - nkm->k.offset) << nkm->k.shift;
    173	reg |= (_nkm.m - nkm->m.offset) << nkm->m.shift;
    174	writel(reg, nkm->common.base + nkm->common.reg);
    175
    176	spin_unlock_irqrestore(nkm->common.lock, flags);
    177
    178	ccu_helper_wait_for_lock(&nkm->common, nkm->lock);
    179
    180	return 0;
    181}
    182
    183static u8 ccu_nkm_get_parent(struct clk_hw *hw)
    184{
    185	struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
    186
    187	return ccu_mux_helper_get_parent(&nkm->common, &nkm->mux);
    188}
    189
    190static int ccu_nkm_set_parent(struct clk_hw *hw, u8 index)
    191{
    192	struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
    193
    194	return ccu_mux_helper_set_parent(&nkm->common, &nkm->mux, index);
    195}
    196
    197const struct clk_ops ccu_nkm_ops = {
    198	.disable	= ccu_nkm_disable,
    199	.enable		= ccu_nkm_enable,
    200	.is_enabled	= ccu_nkm_is_enabled,
    201
    202	.get_parent	= ccu_nkm_get_parent,
    203	.set_parent	= ccu_nkm_set_parent,
    204
    205	.determine_rate	= ccu_nkm_determine_rate,
    206	.recalc_rate	= ccu_nkm_recalc_rate,
    207	.set_rate	= ccu_nkm_set_rate,
    208};
    209EXPORT_SYMBOL_NS_GPL(ccu_nkm_ops, SUNXI_CCU);