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-pll.c (7820B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
      4 */
      5
      6#include <linux/kernel.h>
      7#include <linux/bitops.h>
      8#include <linux/err.h>
      9#include <linux/bug.h>
     10#include <linux/delay.h>
     11#include <linux/export.h>
     12#include <linux/clk-provider.h>
     13#include <linux/regmap.h>
     14
     15#include <asm/div64.h>
     16
     17#include "clk-pll.h"
     18#include "common.h"
     19
     20#define PLL_OUTCTRL		BIT(0)
     21#define PLL_BYPASSNL		BIT(1)
     22#define PLL_RESET_N		BIT(2)
     23
     24static int clk_pll_enable(struct clk_hw *hw)
     25{
     26	struct clk_pll *pll = to_clk_pll(hw);
     27	int ret;
     28	u32 mask, val;
     29
     30	mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
     31	ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &val);
     32	if (ret)
     33		return ret;
     34
     35	/* Skip if already enabled or in FSM mode */
     36	if ((val & mask) == mask || val & PLL_VOTE_FSM_ENA)
     37		return 0;
     38
     39	/* Disable PLL bypass mode. */
     40	ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL,
     41				 PLL_BYPASSNL);
     42	if (ret)
     43		return ret;
     44
     45	/*
     46	 * H/W requires a 5us delay between disabling the bypass and
     47	 * de-asserting the reset. Delay 10us just to be safe.
     48	 */
     49	udelay(10);
     50
     51	/* De-assert active-low PLL reset. */
     52	ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N,
     53				 PLL_RESET_N);
     54	if (ret)
     55		return ret;
     56
     57	/* Wait until PLL is locked. */
     58	udelay(50);
     59
     60	/* Enable PLL output. */
     61	return regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL,
     62				 PLL_OUTCTRL);
     63}
     64
     65static void clk_pll_disable(struct clk_hw *hw)
     66{
     67	struct clk_pll *pll = to_clk_pll(hw);
     68	u32 mask;
     69	u32 val;
     70
     71	regmap_read(pll->clkr.regmap, pll->mode_reg, &val);
     72	/* Skip if in FSM mode */
     73	if (val & PLL_VOTE_FSM_ENA)
     74		return;
     75	mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
     76	regmap_update_bits(pll->clkr.regmap, pll->mode_reg, mask, 0);
     77}
     78
     79static unsigned long
     80clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
     81{
     82	struct clk_pll *pll = to_clk_pll(hw);
     83	u32 l, m, n, config;
     84	unsigned long rate;
     85	u64 tmp;
     86
     87	regmap_read(pll->clkr.regmap, pll->l_reg, &l);
     88	regmap_read(pll->clkr.regmap, pll->m_reg, &m);
     89	regmap_read(pll->clkr.regmap, pll->n_reg, &n);
     90
     91	l &= 0x3ff;
     92	m &= 0x7ffff;
     93	n &= 0x7ffff;
     94
     95	rate = parent_rate * l;
     96	if (n) {
     97		tmp = parent_rate;
     98		tmp *= m;
     99		do_div(tmp, n);
    100		rate += tmp;
    101	}
    102	if (pll->post_div_width) {
    103		regmap_read(pll->clkr.regmap, pll->config_reg, &config);
    104		config >>= pll->post_div_shift;
    105		config &= BIT(pll->post_div_width) - 1;
    106		rate /= config + 1;
    107	}
    108
    109	return rate;
    110}
    111
    112static const
    113struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
    114{
    115	if (!f)
    116		return NULL;
    117
    118	for (; f->freq; f++)
    119		if (rate <= f->freq)
    120			return f;
    121
    122	return NULL;
    123}
    124
    125static int
    126clk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
    127{
    128	struct clk_pll *pll = to_clk_pll(hw);
    129	const struct pll_freq_tbl *f;
    130
    131	f = find_freq(pll->freq_tbl, req->rate);
    132	if (!f)
    133		req->rate = clk_pll_recalc_rate(hw, req->best_parent_rate);
    134	else
    135		req->rate = f->freq;
    136
    137	return 0;
    138}
    139
    140static int
    141clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
    142{
    143	struct clk_pll *pll = to_clk_pll(hw);
    144	const struct pll_freq_tbl *f;
    145	bool enabled;
    146	u32 mode;
    147	u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
    148
    149	f = find_freq(pll->freq_tbl, rate);
    150	if (!f)
    151		return -EINVAL;
    152
    153	regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
    154	enabled = (mode & enable_mask) == enable_mask;
    155
    156	if (enabled)
    157		clk_pll_disable(hw);
    158
    159	regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
    160	regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
    161	regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
    162	regmap_write(pll->clkr.regmap, pll->config_reg, f->ibits);
    163
    164	if (enabled)
    165		clk_pll_enable(hw);
    166
    167	return 0;
    168}
    169
    170const struct clk_ops clk_pll_ops = {
    171	.enable = clk_pll_enable,
    172	.disable = clk_pll_disable,
    173	.recalc_rate = clk_pll_recalc_rate,
    174	.determine_rate = clk_pll_determine_rate,
    175	.set_rate = clk_pll_set_rate,
    176};
    177EXPORT_SYMBOL_GPL(clk_pll_ops);
    178
    179static int wait_for_pll(struct clk_pll *pll)
    180{
    181	u32 val;
    182	int count;
    183	int ret;
    184	const char *name = clk_hw_get_name(&pll->clkr.hw);
    185
    186	/* Wait for pll to enable. */
    187	for (count = 200; count > 0; count--) {
    188		ret = regmap_read(pll->clkr.regmap, pll->status_reg, &val);
    189		if (ret)
    190			return ret;
    191		if (val & BIT(pll->status_bit))
    192			return 0;
    193		udelay(1);
    194	}
    195
    196	WARN(1, "%s didn't enable after voting for it!\n", name);
    197	return -ETIMEDOUT;
    198}
    199
    200static int clk_pll_vote_enable(struct clk_hw *hw)
    201{
    202	int ret;
    203	struct clk_pll *p = to_clk_pll(clk_hw_get_parent(hw));
    204
    205	ret = clk_enable_regmap(hw);
    206	if (ret)
    207		return ret;
    208
    209	return wait_for_pll(p);
    210}
    211
    212const struct clk_ops clk_pll_vote_ops = {
    213	.enable = clk_pll_vote_enable,
    214	.disable = clk_disable_regmap,
    215};
    216EXPORT_SYMBOL_GPL(clk_pll_vote_ops);
    217
    218static void clk_pll_configure(struct clk_pll *pll, struct regmap *regmap,
    219	const struct pll_config *config)
    220{
    221	u32 val;
    222	u32 mask;
    223
    224	regmap_write(regmap, pll->l_reg, config->l);
    225	regmap_write(regmap, pll->m_reg, config->m);
    226	regmap_write(regmap, pll->n_reg, config->n);
    227
    228	val = config->vco_val;
    229	val |= config->pre_div_val;
    230	val |= config->post_div_val;
    231	val |= config->mn_ena_mask;
    232	val |= config->main_output_mask;
    233	val |= config->aux_output_mask;
    234
    235	mask = config->vco_mask;
    236	mask |= config->pre_div_mask;
    237	mask |= config->post_div_mask;
    238	mask |= config->mn_ena_mask;
    239	mask |= config->main_output_mask;
    240	mask |= config->aux_output_mask;
    241
    242	regmap_update_bits(regmap, pll->config_reg, mask, val);
    243}
    244
    245void clk_pll_configure_sr(struct clk_pll *pll, struct regmap *regmap,
    246		const struct pll_config *config, bool fsm_mode)
    247{
    248	clk_pll_configure(pll, regmap, config);
    249	if (fsm_mode)
    250		qcom_pll_set_fsm_mode(regmap, pll->mode_reg, 1, 8);
    251}
    252EXPORT_SYMBOL_GPL(clk_pll_configure_sr);
    253
    254void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap,
    255		const struct pll_config *config, bool fsm_mode)
    256{
    257	clk_pll_configure(pll, regmap, config);
    258	if (fsm_mode)
    259		qcom_pll_set_fsm_mode(regmap, pll->mode_reg, 1, 0);
    260}
    261EXPORT_SYMBOL_GPL(clk_pll_configure_sr_hpm_lp);
    262
    263static int clk_pll_sr2_enable(struct clk_hw *hw)
    264{
    265	struct clk_pll *pll = to_clk_pll(hw);
    266	int ret;
    267	u32 mode;
    268
    269	ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
    270	if (ret)
    271		return ret;
    272
    273	/* Disable PLL bypass mode. */
    274	ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL,
    275				 PLL_BYPASSNL);
    276	if (ret)
    277		return ret;
    278
    279	/*
    280	 * H/W requires a 5us delay between disabling the bypass and
    281	 * de-asserting the reset. Delay 10us just to be safe.
    282	 */
    283	udelay(10);
    284
    285	/* De-assert active-low PLL reset. */
    286	ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N,
    287				 PLL_RESET_N);
    288	if (ret)
    289		return ret;
    290
    291	ret = wait_for_pll(pll);
    292	if (ret)
    293		return ret;
    294
    295	/* Enable PLL output. */
    296	return regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL,
    297				 PLL_OUTCTRL);
    298}
    299
    300static int
    301clk_pll_sr2_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
    302{
    303	struct clk_pll *pll = to_clk_pll(hw);
    304	const struct pll_freq_tbl *f;
    305	bool enabled;
    306	u32 mode;
    307	u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
    308
    309	f = find_freq(pll->freq_tbl, rate);
    310	if (!f)
    311		return -EINVAL;
    312
    313	regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
    314	enabled = (mode & enable_mask) == enable_mask;
    315
    316	if (enabled)
    317		clk_pll_disable(hw);
    318
    319	regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
    320	regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
    321	regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
    322
    323	if (enabled)
    324		clk_pll_sr2_enable(hw);
    325
    326	return 0;
    327}
    328
    329const struct clk_ops clk_pll_sr2_ops = {
    330	.enable = clk_pll_sr2_enable,
    331	.disable = clk_pll_disable,
    332	.set_rate = clk_pll_sr2_set_rate,
    333	.recalc_rate = clk_pll_recalc_rate,
    334	.determine_rate = clk_pll_determine_rate,
    335};
    336EXPORT_SYMBOL_GPL(clk_pll_sr2_ops);