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-pllv2.c (6506B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/kernel.h>
      3#include <linux/clk.h>
      4#include <linux/io.h>
      5#include <linux/errno.h>
      6#include <linux/delay.h>
      7#include <linux/slab.h>
      8#include <linux/err.h>
      9
     10#include <asm/div64.h>
     11
     12#include "clk.h"
     13
     14#define to_clk_pllv2(clk) (container_of(clk, struct clk_pllv2, clk))
     15
     16/* PLL Register Offsets */
     17#define MXC_PLL_DP_CTL			0x00
     18#define MXC_PLL_DP_CONFIG		0x04
     19#define MXC_PLL_DP_OP			0x08
     20#define MXC_PLL_DP_MFD			0x0C
     21#define MXC_PLL_DP_MFN			0x10
     22#define MXC_PLL_DP_MFNMINUS		0x14
     23#define MXC_PLL_DP_MFNPLUS		0x18
     24#define MXC_PLL_DP_HFS_OP		0x1C
     25#define MXC_PLL_DP_HFS_MFD		0x20
     26#define MXC_PLL_DP_HFS_MFN		0x24
     27#define MXC_PLL_DP_MFN_TOGC		0x28
     28#define MXC_PLL_DP_DESTAT		0x2c
     29
     30/* PLL Register Bit definitions */
     31#define MXC_PLL_DP_CTL_MUL_CTRL		0x2000
     32#define MXC_PLL_DP_CTL_DPDCK0_2_EN	0x1000
     33#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET	12
     34#define MXC_PLL_DP_CTL_ADE		0x800
     35#define MXC_PLL_DP_CTL_REF_CLK_DIV	0x400
     36#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK	(3 << 8)
     37#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET	8
     38#define MXC_PLL_DP_CTL_HFSM		0x80
     39#define MXC_PLL_DP_CTL_PRE		0x40
     40#define MXC_PLL_DP_CTL_UPEN		0x20
     41#define MXC_PLL_DP_CTL_RST		0x10
     42#define MXC_PLL_DP_CTL_RCP		0x8
     43#define MXC_PLL_DP_CTL_PLM		0x4
     44#define MXC_PLL_DP_CTL_BRM0		0x2
     45#define MXC_PLL_DP_CTL_LRF		0x1
     46
     47#define MXC_PLL_DP_CONFIG_BIST		0x8
     48#define MXC_PLL_DP_CONFIG_SJC_CE	0x4
     49#define MXC_PLL_DP_CONFIG_AREN		0x2
     50#define MXC_PLL_DP_CONFIG_LDREQ		0x1
     51
     52#define MXC_PLL_DP_OP_MFI_OFFSET	4
     53#define MXC_PLL_DP_OP_MFI_MASK		(0xF << 4)
     54#define MXC_PLL_DP_OP_PDF_OFFSET	0
     55#define MXC_PLL_DP_OP_PDF_MASK		0xF
     56
     57#define MXC_PLL_DP_MFD_OFFSET		0
     58#define MXC_PLL_DP_MFD_MASK		0x07FFFFFF
     59
     60#define MXC_PLL_DP_MFN_OFFSET		0x0
     61#define MXC_PLL_DP_MFN_MASK		0x07FFFFFF
     62
     63#define MXC_PLL_DP_MFN_TOGC_TOG_DIS	(1 << 17)
     64#define MXC_PLL_DP_MFN_TOGC_TOG_EN	(1 << 16)
     65#define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET	0x0
     66#define MXC_PLL_DP_MFN_TOGC_CNT_MASK	0xFFFF
     67
     68#define MXC_PLL_DP_DESTAT_TOG_SEL	(1 << 31)
     69#define MXC_PLL_DP_DESTAT_MFN		0x07FFFFFF
     70
     71#define MAX_DPLL_WAIT_TRIES	1000 /* 1000 * udelay(1) = 1ms */
     72
     73struct clk_pllv2 {
     74	struct clk_hw	hw;
     75	void __iomem	*base;
     76};
     77
     78static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate,
     79		u32 dp_ctl, u32 dp_op, u32 dp_mfd, u32 dp_mfn)
     80{
     81	long mfi, mfn, mfd, pdf, ref_clk;
     82	unsigned long dbl;
     83	u64 temp;
     84
     85	dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN;
     86
     87	pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK;
     88	mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET;
     89	mfi = (mfi <= 5) ? 5 : mfi;
     90	mfd = dp_mfd & MXC_PLL_DP_MFD_MASK;
     91	mfn = dp_mfn & MXC_PLL_DP_MFN_MASK;
     92	mfn = sign_extend32(mfn, 26);
     93
     94	ref_clk = 2 * parent_rate;
     95	if (dbl != 0)
     96		ref_clk *= 2;
     97
     98	ref_clk /= (pdf + 1);
     99	temp = (u64) ref_clk * abs(mfn);
    100	do_div(temp, mfd + 1);
    101	if (mfn < 0)
    102		temp = (ref_clk * mfi) - temp;
    103	else
    104		temp = (ref_clk * mfi) + temp;
    105
    106	return temp;
    107}
    108
    109static unsigned long clk_pllv2_recalc_rate(struct clk_hw *hw,
    110		unsigned long parent_rate)
    111{
    112	u32 dp_op, dp_mfd, dp_mfn, dp_ctl;
    113	void __iomem *pllbase;
    114	struct clk_pllv2 *pll = to_clk_pllv2(hw);
    115
    116	pllbase = pll->base;
    117
    118	dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
    119	dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP);
    120	dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD);
    121	dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN);
    122
    123	return __clk_pllv2_recalc_rate(parent_rate, dp_ctl, dp_op, dp_mfd, dp_mfn);
    124}
    125
    126static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate,
    127		u32 *dp_op, u32 *dp_mfd, u32 *dp_mfn)
    128{
    129	u32 reg;
    130	long mfi, pdf, mfn, mfd = 999999;
    131	u64 temp64;
    132	unsigned long quad_parent_rate;
    133
    134	quad_parent_rate = 4 * parent_rate;
    135	pdf = mfi = -1;
    136	while (++pdf < 16 && mfi < 5)
    137		mfi = rate * (pdf+1) / quad_parent_rate;
    138	if (mfi > 15)
    139		return -EINVAL;
    140	pdf--;
    141
    142	temp64 = rate * (pdf + 1) - quad_parent_rate * mfi;
    143	do_div(temp64, quad_parent_rate / 1000000);
    144	mfn = (long)temp64;
    145
    146	reg = mfi << 4 | pdf;
    147
    148	*dp_op = reg;
    149	*dp_mfd = mfd;
    150	*dp_mfn = mfn;
    151
    152	return 0;
    153}
    154
    155static int clk_pllv2_set_rate(struct clk_hw *hw, unsigned long rate,
    156		unsigned long parent_rate)
    157{
    158	struct clk_pllv2 *pll = to_clk_pllv2(hw);
    159	void __iomem *pllbase;
    160	u32 dp_ctl, dp_op, dp_mfd, dp_mfn;
    161	int ret;
    162
    163	pllbase = pll->base;
    164
    165
    166	ret = __clk_pllv2_set_rate(rate, parent_rate, &dp_op, &dp_mfd, &dp_mfn);
    167	if (ret)
    168		return ret;
    169
    170	dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
    171	/* use dpdck0_2 */
    172	__raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL);
    173
    174	__raw_writel(dp_op, pllbase + MXC_PLL_DP_OP);
    175	__raw_writel(dp_mfd, pllbase + MXC_PLL_DP_MFD);
    176	__raw_writel(dp_mfn, pllbase + MXC_PLL_DP_MFN);
    177
    178	return 0;
    179}
    180
    181static long clk_pllv2_round_rate(struct clk_hw *hw, unsigned long rate,
    182		unsigned long *prate)
    183{
    184	u32 dp_op, dp_mfd, dp_mfn;
    185	int ret;
    186
    187	ret = __clk_pllv2_set_rate(rate, *prate, &dp_op, &dp_mfd, &dp_mfn);
    188	if (ret)
    189		return ret;
    190
    191	return __clk_pllv2_recalc_rate(*prate, MXC_PLL_DP_CTL_DPDCK0_2_EN,
    192			dp_op, dp_mfd, dp_mfn);
    193}
    194
    195static int clk_pllv2_prepare(struct clk_hw *hw)
    196{
    197	struct clk_pllv2 *pll = to_clk_pllv2(hw);
    198	u32 reg;
    199	void __iomem *pllbase;
    200	int i = 0;
    201
    202	pllbase = pll->base;
    203	reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN;
    204	__raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
    205
    206	/* Wait for lock */
    207	do {
    208		reg = __raw_readl(pllbase + MXC_PLL_DP_CTL);
    209		if (reg & MXC_PLL_DP_CTL_LRF)
    210			break;
    211
    212		udelay(1);
    213	} while (++i < MAX_DPLL_WAIT_TRIES);
    214
    215	if (i == MAX_DPLL_WAIT_TRIES) {
    216		pr_err("MX5: pll locking failed\n");
    217		return -EINVAL;
    218	}
    219
    220	return 0;
    221}
    222
    223static void clk_pllv2_unprepare(struct clk_hw *hw)
    224{
    225	struct clk_pllv2 *pll = to_clk_pllv2(hw);
    226	u32 reg;
    227	void __iomem *pllbase;
    228
    229	pllbase = pll->base;
    230	reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN;
    231	__raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
    232}
    233
    234static const struct clk_ops clk_pllv2_ops = {
    235	.prepare = clk_pllv2_prepare,
    236	.unprepare = clk_pllv2_unprepare,
    237	.recalc_rate = clk_pllv2_recalc_rate,
    238	.round_rate = clk_pllv2_round_rate,
    239	.set_rate = clk_pllv2_set_rate,
    240};
    241
    242struct clk_hw *imx_clk_hw_pllv2(const char *name, const char *parent,
    243		void __iomem *base)
    244{
    245	struct clk_pllv2 *pll;
    246	struct clk_hw *hw;
    247	struct clk_init_data init;
    248	int ret;
    249
    250	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
    251	if (!pll)
    252		return ERR_PTR(-ENOMEM);
    253
    254	pll->base = base;
    255
    256	init.name = name;
    257	init.ops = &clk_pllv2_ops;
    258	init.flags = 0;
    259	init.parent_names = &parent;
    260	init.num_parents = 1;
    261
    262	pll->hw.init = &init;
    263	hw = &pll->hw;
    264
    265	ret = clk_hw_register(NULL, hw);
    266	if (ret) {
    267		kfree(pll);
    268		return ERR_PTR(ret);
    269	}
    270
    271	return hw;
    272}