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

pll.c (5511B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Zynq PLL driver
      4 *
      5 *  Copyright (C) 2013 Xilinx
      6 *
      7 *  Sören Brinkmann <soren.brinkmann@xilinx.com>
      8 */
      9#include <linux/clk/zynq.h>
     10#include <linux/clk-provider.h>
     11#include <linux/slab.h>
     12#include <linux/io.h>
     13
     14/**
     15 * struct zynq_pll - pll clock
     16 * @hw:		Handle between common and hardware-specific interfaces
     17 * @pll_ctrl:	PLL control register
     18 * @pll_status:	PLL status register
     19 * @lock:	Register lock
     20 * @lockbit:	Indicates the associated PLL_LOCKED bit in the PLL status
     21 *		register.
     22 */
     23struct zynq_pll {
     24	struct clk_hw	hw;
     25	void __iomem	*pll_ctrl;
     26	void __iomem	*pll_status;
     27	spinlock_t	*lock;
     28	u8		lockbit;
     29};
     30#define to_zynq_pll(_hw)	container_of(_hw, struct zynq_pll, hw)
     31
     32/* Register bitfield defines */
     33#define PLLCTRL_FBDIV_MASK	0x7f000
     34#define PLLCTRL_FBDIV_SHIFT	12
     35#define PLLCTRL_BPQUAL_MASK	(1 << 3)
     36#define PLLCTRL_PWRDWN_MASK	2
     37#define PLLCTRL_PWRDWN_SHIFT	1
     38#define PLLCTRL_RESET_MASK	1
     39#define PLLCTRL_RESET_SHIFT	0
     40
     41#define PLL_FBDIV_MIN	13
     42#define PLL_FBDIV_MAX	66
     43
     44/**
     45 * zynq_pll_round_rate() - Round a clock frequency
     46 * @hw:		Handle between common and hardware-specific interfaces
     47 * @rate:	Desired clock frequency
     48 * @prate:	Clock frequency of parent clock
     49 * Return:	frequency closest to @rate the hardware can generate.
     50 */
     51static long zynq_pll_round_rate(struct clk_hw *hw, unsigned long rate,
     52		unsigned long *prate)
     53{
     54	u32 fbdiv;
     55
     56	fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
     57	if (fbdiv < PLL_FBDIV_MIN)
     58		fbdiv = PLL_FBDIV_MIN;
     59	else if (fbdiv > PLL_FBDIV_MAX)
     60		fbdiv = PLL_FBDIV_MAX;
     61
     62	return *prate * fbdiv;
     63}
     64
     65/**
     66 * zynq_pll_recalc_rate() - Recalculate clock frequency
     67 * @hw:			Handle between common and hardware-specific interfaces
     68 * @parent_rate:	Clock frequency of parent clock
     69 * Return:		current clock frequency.
     70 */
     71static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw,
     72		unsigned long parent_rate)
     73{
     74	struct zynq_pll *clk = to_zynq_pll(hw);
     75	u32 fbdiv;
     76
     77	/*
     78	 * makes probably sense to redundantly save fbdiv in the struct
     79	 * zynq_pll to save the IO access.
     80	 */
     81	fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >>
     82			PLLCTRL_FBDIV_SHIFT;
     83
     84	return parent_rate * fbdiv;
     85}
     86
     87/**
     88 * zynq_pll_is_enabled - Check if a clock is enabled
     89 * @hw:		Handle between common and hardware-specific interfaces
     90 * Return:	1 if the clock is enabled, 0 otherwise.
     91 *
     92 * Not sure this is a good idea, but since disabled means bypassed for
     93 * this clock implementation we say we are always enabled.
     94 */
     95static int zynq_pll_is_enabled(struct clk_hw *hw)
     96{
     97	unsigned long flags = 0;
     98	u32 reg;
     99	struct zynq_pll *clk = to_zynq_pll(hw);
    100
    101	spin_lock_irqsave(clk->lock, flags);
    102
    103	reg = readl(clk->pll_ctrl);
    104
    105	spin_unlock_irqrestore(clk->lock, flags);
    106
    107	return !(reg & (PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK));
    108}
    109
    110/**
    111 * zynq_pll_enable - Enable clock
    112 * @hw:		Handle between common and hardware-specific interfaces
    113 * Return: 0 on success
    114 */
    115static int zynq_pll_enable(struct clk_hw *hw)
    116{
    117	unsigned long flags = 0;
    118	u32 reg;
    119	struct zynq_pll *clk = to_zynq_pll(hw);
    120
    121	if (zynq_pll_is_enabled(hw))
    122		return 0;
    123
    124	pr_info("PLL: enable\n");
    125
    126	/* Power up PLL and wait for lock */
    127	spin_lock_irqsave(clk->lock, flags);
    128
    129	reg = readl(clk->pll_ctrl);
    130	reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK);
    131	writel(reg, clk->pll_ctrl);
    132	while (!(readl(clk->pll_status) & (1 << clk->lockbit)))
    133		;
    134
    135	spin_unlock_irqrestore(clk->lock, flags);
    136
    137	return 0;
    138}
    139
    140/**
    141 * zynq_pll_disable - Disable clock
    142 * @hw:		Handle between common and hardware-specific interfaces
    143 * Returns 0 on success
    144 */
    145static void zynq_pll_disable(struct clk_hw *hw)
    146{
    147	unsigned long flags = 0;
    148	u32 reg;
    149	struct zynq_pll *clk = to_zynq_pll(hw);
    150
    151	if (!zynq_pll_is_enabled(hw))
    152		return;
    153
    154	pr_info("PLL: shutdown\n");
    155
    156	/* shut down PLL */
    157	spin_lock_irqsave(clk->lock, flags);
    158
    159	reg = readl(clk->pll_ctrl);
    160	reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK;
    161	writel(reg, clk->pll_ctrl);
    162
    163	spin_unlock_irqrestore(clk->lock, flags);
    164}
    165
    166static const struct clk_ops zynq_pll_ops = {
    167	.enable = zynq_pll_enable,
    168	.disable = zynq_pll_disable,
    169	.is_enabled = zynq_pll_is_enabled,
    170	.round_rate = zynq_pll_round_rate,
    171	.recalc_rate = zynq_pll_recalc_rate
    172};
    173
    174/**
    175 * clk_register_zynq_pll() - Register PLL with the clock framework
    176 * @name:	PLL name
    177 * @parent:	Parent clock name
    178 * @pll_ctrl:	Pointer to PLL control register
    179 * @pll_status:	Pointer to PLL status register
    180 * @lock_index:	Bit index to this PLL's lock status bit in @pll_status
    181 * @lock:	Register lock
    182 * Return:	handle to the registered clock.
    183 */
    184struct clk *clk_register_zynq_pll(const char *name, const char *parent,
    185		void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index,
    186		spinlock_t *lock)
    187{
    188	struct zynq_pll *pll;
    189	struct clk *clk;
    190	u32 reg;
    191	const char *parent_arr[1] = {parent};
    192	unsigned long flags = 0;
    193	struct clk_init_data initd = {
    194		.name = name,
    195		.parent_names = parent_arr,
    196		.ops = &zynq_pll_ops,
    197		.num_parents = 1,
    198		.flags = 0
    199	};
    200
    201	pll = kmalloc(sizeof(*pll), GFP_KERNEL);
    202	if (!pll)
    203		return ERR_PTR(-ENOMEM);
    204
    205	/* Populate the struct */
    206	pll->hw.init = &initd;
    207	pll->pll_ctrl = pll_ctrl;
    208	pll->pll_status = pll_status;
    209	pll->lockbit = lock_index;
    210	pll->lock = lock;
    211
    212	spin_lock_irqsave(pll->lock, flags);
    213
    214	reg = readl(pll->pll_ctrl);
    215	reg &= ~PLLCTRL_BPQUAL_MASK;
    216	writel(reg, pll->pll_ctrl);
    217
    218	spin_unlock_irqrestore(pll->lock, flags);
    219
    220	clk = clk_register(NULL, &pll->hw);
    221	if (WARN_ON(IS_ERR(clk)))
    222		goto free_pll;
    223
    224	return clk;
    225
    226free_pll:
    227	kfree(pll);
    228
    229	return clk;
    230}