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 (10737B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2014 MediaTek Inc.
      4 * Author: James Liao <jamesjj.liao@mediatek.com>
      5 */
      6
      7#include <linux/clk-provider.h>
      8#include <linux/container_of.h>
      9#include <linux/delay.h>
     10#include <linux/err.h>
     11#include <linux/io.h>
     12#include <linux/module.h>
     13#include <linux/of_address.h>
     14#include <linux/slab.h>
     15
     16#include "clk-pll.h"
     17
     18#define MHZ			(1000 * 1000)
     19
     20#define REG_CON0		0
     21#define REG_CON1		4
     22
     23#define CON0_BASE_EN		BIT(0)
     24#define CON0_PWR_ON		BIT(0)
     25#define CON0_ISO_EN		BIT(1)
     26#define PCW_CHG_MASK		BIT(31)
     27
     28#define AUDPLL_TUNER_EN		BIT(31)
     29
     30#define POSTDIV_MASK		0x7
     31
     32/* default 7 bits integer, can be overridden with pcwibits. */
     33#define INTEGER_BITS		7
     34
     35/*
     36 * MediaTek PLLs are configured through their pcw value. The pcw value describes
     37 * a divider in the PLL feedback loop which consists of 7 bits for the integer
     38 * part and the remaining bits (if present) for the fractional part. Also they
     39 * have a 3 bit power-of-two post divider.
     40 */
     41
     42struct mtk_clk_pll {
     43	struct clk_hw	hw;
     44	void __iomem	*base_addr;
     45	void __iomem	*pd_addr;
     46	void __iomem	*pwr_addr;
     47	void __iomem	*tuner_addr;
     48	void __iomem	*tuner_en_addr;
     49	void __iomem	*pcw_addr;
     50	void __iomem	*pcw_chg_addr;
     51	void __iomem	*en_addr;
     52	const struct mtk_pll_data *data;
     53};
     54
     55static inline struct mtk_clk_pll *to_mtk_clk_pll(struct clk_hw *hw)
     56{
     57	return container_of(hw, struct mtk_clk_pll, hw);
     58}
     59
     60static int mtk_pll_is_prepared(struct clk_hw *hw)
     61{
     62	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
     63
     64	return (readl(pll->en_addr) & BIT(pll->data->pll_en_bit)) != 0;
     65}
     66
     67static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin,
     68		u32 pcw, int postdiv)
     69{
     70	int pcwbits = pll->data->pcwbits;
     71	int pcwfbits = 0;
     72	int ibits;
     73	u64 vco;
     74	u8 c = 0;
     75
     76	/* The fractional part of the PLL divider. */
     77	ibits = pll->data->pcwibits ? pll->data->pcwibits : INTEGER_BITS;
     78	if (pcwbits > ibits)
     79		pcwfbits = pcwbits - ibits;
     80
     81	vco = (u64)fin * pcw;
     82
     83	if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0)))
     84		c = 1;
     85
     86	vco >>= pcwfbits;
     87
     88	if (c)
     89		vco++;
     90
     91	return ((unsigned long)vco + postdiv - 1) / postdiv;
     92}
     93
     94static void __mtk_pll_tuner_enable(struct mtk_clk_pll *pll)
     95{
     96	u32 r;
     97
     98	if (pll->tuner_en_addr) {
     99		r = readl(pll->tuner_en_addr) | BIT(pll->data->tuner_en_bit);
    100		writel(r, pll->tuner_en_addr);
    101	} else if (pll->tuner_addr) {
    102		r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN;
    103		writel(r, pll->tuner_addr);
    104	}
    105}
    106
    107static void __mtk_pll_tuner_disable(struct mtk_clk_pll *pll)
    108{
    109	u32 r;
    110
    111	if (pll->tuner_en_addr) {
    112		r = readl(pll->tuner_en_addr) & ~BIT(pll->data->tuner_en_bit);
    113		writel(r, pll->tuner_en_addr);
    114	} else if (pll->tuner_addr) {
    115		r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN;
    116		writel(r, pll->tuner_addr);
    117	}
    118}
    119
    120static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
    121		int postdiv)
    122{
    123	u32 chg, val;
    124
    125	/* disable tuner */
    126	__mtk_pll_tuner_disable(pll);
    127
    128	/* set postdiv */
    129	val = readl(pll->pd_addr);
    130	val &= ~(POSTDIV_MASK << pll->data->pd_shift);
    131	val |= (ffs(postdiv) - 1) << pll->data->pd_shift;
    132
    133	/* postdiv and pcw need to set at the same time if on same register */
    134	if (pll->pd_addr != pll->pcw_addr) {
    135		writel(val, pll->pd_addr);
    136		val = readl(pll->pcw_addr);
    137	}
    138
    139	/* set pcw */
    140	val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1,
    141			pll->data->pcw_shift);
    142	val |= pcw << pll->data->pcw_shift;
    143	writel(val, pll->pcw_addr);
    144	chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK;
    145	writel(chg, pll->pcw_chg_addr);
    146	if (pll->tuner_addr)
    147		writel(val + 1, pll->tuner_addr);
    148
    149	/* restore tuner_en */
    150	__mtk_pll_tuner_enable(pll);
    151
    152	udelay(20);
    153}
    154
    155/*
    156 * mtk_pll_calc_values - calculate good values for a given input frequency.
    157 * @pll:	The pll
    158 * @pcw:	The pcw value (output)
    159 * @postdiv:	The post divider (output)
    160 * @freq:	The desired target frequency
    161 * @fin:	The input frequency
    162 *
    163 */
    164static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv,
    165		u32 freq, u32 fin)
    166{
    167	unsigned long fmin = pll->data->fmin ? pll->data->fmin : (1000 * MHZ);
    168	const struct mtk_pll_div_table *div_table = pll->data->div_table;
    169	u64 _pcw;
    170	int ibits;
    171	u32 val;
    172
    173	if (freq > pll->data->fmax)
    174		freq = pll->data->fmax;
    175
    176	if (div_table) {
    177		if (freq > div_table[0].freq)
    178			freq = div_table[0].freq;
    179
    180		for (val = 0; div_table[val + 1].freq != 0; val++) {
    181			if (freq > div_table[val + 1].freq)
    182				break;
    183		}
    184		*postdiv = 1 << val;
    185	} else {
    186		for (val = 0; val < 5; val++) {
    187			*postdiv = 1 << val;
    188			if ((u64)freq * *postdiv >= fmin)
    189				break;
    190		}
    191	}
    192
    193	/* _pcw = freq * postdiv / fin * 2^pcwfbits */
    194	ibits = pll->data->pcwibits ? pll->data->pcwibits : INTEGER_BITS;
    195	_pcw = ((u64)freq << val) << (pll->data->pcwbits - ibits);
    196	do_div(_pcw, fin);
    197
    198	*pcw = (u32)_pcw;
    199}
    200
    201static int mtk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
    202		unsigned long parent_rate)
    203{
    204	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
    205	u32 pcw = 0;
    206	u32 postdiv;
    207
    208	mtk_pll_calc_values(pll, &pcw, &postdiv, rate, parent_rate);
    209	mtk_pll_set_rate_regs(pll, pcw, postdiv);
    210
    211	return 0;
    212}
    213
    214static unsigned long mtk_pll_recalc_rate(struct clk_hw *hw,
    215		unsigned long parent_rate)
    216{
    217	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
    218	u32 postdiv;
    219	u32 pcw;
    220
    221	postdiv = (readl(pll->pd_addr) >> pll->data->pd_shift) & POSTDIV_MASK;
    222	postdiv = 1 << postdiv;
    223
    224	pcw = readl(pll->pcw_addr) >> pll->data->pcw_shift;
    225	pcw &= GENMASK(pll->data->pcwbits - 1, 0);
    226
    227	return __mtk_pll_recalc_rate(pll, parent_rate, pcw, postdiv);
    228}
    229
    230static long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
    231		unsigned long *prate)
    232{
    233	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
    234	u32 pcw = 0;
    235	int postdiv;
    236
    237	mtk_pll_calc_values(pll, &pcw, &postdiv, rate, *prate);
    238
    239	return __mtk_pll_recalc_rate(pll, *prate, pcw, postdiv);
    240}
    241
    242static int mtk_pll_prepare(struct clk_hw *hw)
    243{
    244	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
    245	u32 r;
    246
    247	r = readl(pll->pwr_addr) | CON0_PWR_ON;
    248	writel(r, pll->pwr_addr);
    249	udelay(1);
    250
    251	r = readl(pll->pwr_addr) & ~CON0_ISO_EN;
    252	writel(r, pll->pwr_addr);
    253	udelay(1);
    254
    255	r = readl(pll->en_addr) | BIT(pll->data->pll_en_bit);
    256	writel(r, pll->en_addr);
    257
    258	if (pll->data->en_mask) {
    259		r = readl(pll->base_addr + REG_CON0) | pll->data->en_mask;
    260		writel(r, pll->base_addr + REG_CON0);
    261	}
    262
    263	__mtk_pll_tuner_enable(pll);
    264
    265	udelay(20);
    266
    267	if (pll->data->flags & HAVE_RST_BAR) {
    268		r = readl(pll->base_addr + REG_CON0);
    269		r |= pll->data->rst_bar_mask;
    270		writel(r, pll->base_addr + REG_CON0);
    271	}
    272
    273	return 0;
    274}
    275
    276static void mtk_pll_unprepare(struct clk_hw *hw)
    277{
    278	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
    279	u32 r;
    280
    281	if (pll->data->flags & HAVE_RST_BAR) {
    282		r = readl(pll->base_addr + REG_CON0);
    283		r &= ~pll->data->rst_bar_mask;
    284		writel(r, pll->base_addr + REG_CON0);
    285	}
    286
    287	__mtk_pll_tuner_disable(pll);
    288
    289	if (pll->data->en_mask) {
    290		r = readl(pll->base_addr + REG_CON0) & ~pll->data->en_mask;
    291		writel(r, pll->base_addr + REG_CON0);
    292	}
    293
    294	r = readl(pll->en_addr) & ~BIT(pll->data->pll_en_bit);
    295	writel(r, pll->en_addr);
    296
    297	r = readl(pll->pwr_addr) | CON0_ISO_EN;
    298	writel(r, pll->pwr_addr);
    299
    300	r = readl(pll->pwr_addr) & ~CON0_PWR_ON;
    301	writel(r, pll->pwr_addr);
    302}
    303
    304static const struct clk_ops mtk_pll_ops = {
    305	.is_prepared	= mtk_pll_is_prepared,
    306	.prepare	= mtk_pll_prepare,
    307	.unprepare	= mtk_pll_unprepare,
    308	.recalc_rate	= mtk_pll_recalc_rate,
    309	.round_rate	= mtk_pll_round_rate,
    310	.set_rate	= mtk_pll_set_rate,
    311};
    312
    313static struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data,
    314		void __iomem *base)
    315{
    316	struct mtk_clk_pll *pll;
    317	struct clk_init_data init = {};
    318	int ret;
    319	const char *parent_name = "clk26m";
    320
    321	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
    322	if (!pll)
    323		return ERR_PTR(-ENOMEM);
    324
    325	pll->base_addr = base + data->reg;
    326	pll->pwr_addr = base + data->pwr_reg;
    327	pll->pd_addr = base + data->pd_reg;
    328	pll->pcw_addr = base + data->pcw_reg;
    329	if (data->pcw_chg_reg)
    330		pll->pcw_chg_addr = base + data->pcw_chg_reg;
    331	else
    332		pll->pcw_chg_addr = pll->base_addr + REG_CON1;
    333	if (data->tuner_reg)
    334		pll->tuner_addr = base + data->tuner_reg;
    335	if (data->tuner_en_reg || data->tuner_en_bit)
    336		pll->tuner_en_addr = base + data->tuner_en_reg;
    337	if (data->en_reg)
    338		pll->en_addr = base + data->en_reg;
    339	else
    340		pll->en_addr = pll->base_addr + REG_CON0;
    341	pll->hw.init = &init;
    342	pll->data = data;
    343
    344	init.name = data->name;
    345	init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0;
    346	init.ops = &mtk_pll_ops;
    347	if (data->parent_name)
    348		init.parent_names = &data->parent_name;
    349	else
    350		init.parent_names = &parent_name;
    351	init.num_parents = 1;
    352
    353	ret = clk_hw_register(NULL, &pll->hw);
    354
    355	if (ret) {
    356		kfree(pll);
    357		return ERR_PTR(ret);
    358	}
    359
    360	return &pll->hw;
    361}
    362
    363static void mtk_clk_unregister_pll(struct clk_hw *hw)
    364{
    365	struct mtk_clk_pll *pll;
    366
    367	if (!hw)
    368		return;
    369
    370	pll = to_mtk_clk_pll(hw);
    371
    372	clk_hw_unregister(hw);
    373	kfree(pll);
    374}
    375
    376int mtk_clk_register_plls(struct device_node *node,
    377			  const struct mtk_pll_data *plls, int num_plls,
    378			  struct clk_hw_onecell_data *clk_data)
    379{
    380	void __iomem *base;
    381	int i;
    382	struct clk_hw *hw;
    383
    384	base = of_iomap(node, 0);
    385	if (!base) {
    386		pr_err("%s(): ioremap failed\n", __func__);
    387		return -EINVAL;
    388	}
    389
    390	for (i = 0; i < num_plls; i++) {
    391		const struct mtk_pll_data *pll = &plls[i];
    392
    393		if (!IS_ERR_OR_NULL(clk_data->hws[pll->id])) {
    394			pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
    395				node, pll->id);
    396			continue;
    397		}
    398
    399		hw = mtk_clk_register_pll(pll, base);
    400
    401		if (IS_ERR(hw)) {
    402			pr_err("Failed to register clk %s: %pe\n", pll->name,
    403			       hw);
    404			goto err;
    405		}
    406
    407		clk_data->hws[pll->id] = hw;
    408	}
    409
    410	return 0;
    411
    412err:
    413	while (--i >= 0) {
    414		const struct mtk_pll_data *pll = &plls[i];
    415
    416		mtk_clk_unregister_pll(clk_data->hws[pll->id]);
    417		clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
    418	}
    419
    420	iounmap(base);
    421
    422	return PTR_ERR(hw);
    423}
    424EXPORT_SYMBOL_GPL(mtk_clk_register_plls);
    425
    426static __iomem void *mtk_clk_pll_get_base(struct clk_hw *hw,
    427					  const struct mtk_pll_data *data)
    428{
    429	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
    430
    431	return pll->base_addr - data->reg;
    432}
    433
    434void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls,
    435			     struct clk_hw_onecell_data *clk_data)
    436{
    437	__iomem void *base = NULL;
    438	int i;
    439
    440	if (!clk_data)
    441		return;
    442
    443	for (i = num_plls; i > 0; i--) {
    444		const struct mtk_pll_data *pll = &plls[i - 1];
    445
    446		if (IS_ERR_OR_NULL(clk_data->hws[pll->id]))
    447			continue;
    448
    449		/*
    450		 * This is quite ugly but unfortunately the clks don't have
    451		 * any device tied to them, so there's no place to store the
    452		 * pointer to the I/O region base address. We have to fetch
    453		 * it from one of the registered clks.
    454		 */
    455		base = mtk_clk_pll_get_base(clk_data->hws[pll->id], pll);
    456
    457		mtk_clk_unregister_pll(clk_data->hws[pll->id]);
    458		clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
    459	}
    460
    461	iounmap(base);
    462}
    463EXPORT_SYMBOL_GPL(mtk_clk_unregister_plls);
    464
    465MODULE_LICENSE("GPL");