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


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2020 Intel Corporation.
      4 * Zhu YiXin <yixin.zhu@intel.com>
      5 * Rahul Tanwar <rahul.tanwar@intel.com>
      6 */
      7
      8#include <linux/clk-provider.h>
      9#include <linux/delay.h>
     10#include <linux/device.h>
     11#include <linux/iopoll.h>
     12#include <linux/of.h>
     13
     14#include "clk-cgu.h"
     15
     16#define to_lgm_clk_pll(_hw)	container_of(_hw, struct lgm_clk_pll, hw)
     17#define PLL_REF_DIV(x)		((x) + 0x08)
     18
     19/*
     20 * Calculate formula:
     21 * rate = (prate * mult + (prate * frac) / frac_div) / div
     22 */
     23static unsigned long
     24lgm_pll_calc_rate(unsigned long prate, unsigned int mult,
     25		  unsigned int div, unsigned int frac, unsigned int frac_div)
     26{
     27	u64 crate, frate, rate64;
     28
     29	rate64 = prate;
     30	crate = rate64 * mult;
     31	frate = rate64 * frac;
     32	do_div(frate, frac_div);
     33	crate += frate;
     34	do_div(crate, div);
     35
     36	return crate;
     37}
     38
     39static unsigned long lgm_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
     40{
     41	struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
     42	unsigned int div, mult, frac;
     43	unsigned long flags;
     44
     45	spin_lock_irqsave(&pll->lock, flags);
     46	mult = lgm_get_clk_val(pll->membase, PLL_REF_DIV(pll->reg), 0, 12);
     47	div = lgm_get_clk_val(pll->membase, PLL_REF_DIV(pll->reg), 18, 6);
     48	frac = lgm_get_clk_val(pll->membase, pll->reg, 2, 24);
     49	spin_unlock_irqrestore(&pll->lock, flags);
     50
     51	if (pll->type == TYPE_LJPLL)
     52		div *= 4;
     53
     54	return lgm_pll_calc_rate(prate, mult, div, frac, BIT(24));
     55}
     56
     57static int lgm_pll_is_enabled(struct clk_hw *hw)
     58{
     59	struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
     60	unsigned long flags;
     61	unsigned int ret;
     62
     63	spin_lock_irqsave(&pll->lock, flags);
     64	ret = lgm_get_clk_val(pll->membase, pll->reg, 0, 1);
     65	spin_unlock_irqrestore(&pll->lock, flags);
     66
     67	return ret;
     68}
     69
     70static int lgm_pll_enable(struct clk_hw *hw)
     71{
     72	struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
     73	unsigned long flags;
     74	u32 val;
     75	int ret;
     76
     77	spin_lock_irqsave(&pll->lock, flags);
     78	lgm_set_clk_val(pll->membase, pll->reg, 0, 1, 1);
     79	ret = readl_poll_timeout_atomic(pll->membase + pll->reg,
     80					val, (val & 0x1), 1, 100);
     81	spin_unlock_irqrestore(&pll->lock, flags);
     82
     83	return ret;
     84}
     85
     86static void lgm_pll_disable(struct clk_hw *hw)
     87{
     88	struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
     89	unsigned long flags;
     90
     91	spin_lock_irqsave(&pll->lock, flags);
     92	lgm_set_clk_val(pll->membase, pll->reg, 0, 1, 0);
     93	spin_unlock_irqrestore(&pll->lock, flags);
     94}
     95
     96static const struct clk_ops lgm_pll_ops = {
     97	.recalc_rate = lgm_pll_recalc_rate,
     98	.is_enabled = lgm_pll_is_enabled,
     99	.enable = lgm_pll_enable,
    100	.disable = lgm_pll_disable,
    101};
    102
    103static struct clk_hw *
    104lgm_clk_register_pll(struct lgm_clk_provider *ctx,
    105		     const struct lgm_pll_clk_data *list)
    106{
    107	struct clk_init_data init = {};
    108	struct lgm_clk_pll *pll;
    109	struct device *dev = ctx->dev;
    110	struct clk_hw *hw;
    111	int ret;
    112
    113	init.ops = &lgm_pll_ops;
    114	init.name = list->name;
    115	init.flags = list->flags;
    116	init.parent_data = list->parent_data;
    117	init.num_parents = list->num_parents;
    118
    119	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
    120	if (!pll)
    121		return ERR_PTR(-ENOMEM);
    122
    123	pll->membase = ctx->membase;
    124	pll->lock = ctx->lock;
    125	pll->reg = list->reg;
    126	pll->flags = list->flags;
    127	pll->type = list->type;
    128	pll->hw.init = &init;
    129
    130	hw = &pll->hw;
    131	ret = devm_clk_hw_register(dev, hw);
    132	if (ret)
    133		return ERR_PTR(ret);
    134
    135	return hw;
    136}
    137
    138int lgm_clk_register_plls(struct lgm_clk_provider *ctx,
    139			  const struct lgm_pll_clk_data *list,
    140			  unsigned int nr_clk)
    141{
    142	struct clk_hw *hw;
    143	int i;
    144
    145	for (i = 0; i < nr_clk; i++, list++) {
    146		hw = lgm_clk_register_pll(ctx, list);
    147		if (IS_ERR(hw)) {
    148			dev_err(ctx->dev, "failed to register pll: %s\n",
    149				list->name);
    150			return PTR_ERR(hw);
    151		}
    152		ctx->clk_data.hws[list->id] = hw;
    153	}
    154
    155	return 0;
    156}