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

owl-pll.c (4249B)


      1// SPDX-License-Identifier: GPL-2.0+
      2//
      3// OWL pll clock driver
      4//
      5// Copyright (c) 2014 Actions Semi Inc.
      6// Author: David Liu <liuwei@actions-semi.com>
      7//
      8// Copyright (c) 2018 Linaro Ltd.
      9// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
     10
     11#include <linux/clk-provider.h>
     12#include <linux/slab.h>
     13#include <linux/io.h>
     14#include <linux/delay.h>
     15
     16#include "owl-pll.h"
     17
     18static u32 owl_pll_calculate_mul(struct owl_pll_hw *pll_hw, unsigned long rate)
     19{
     20	u32 mul;
     21
     22	mul = DIV_ROUND_CLOSEST(rate, pll_hw->bfreq);
     23	if (mul < pll_hw->min_mul)
     24		mul = pll_hw->min_mul;
     25	else if (mul > pll_hw->max_mul)
     26		mul = pll_hw->max_mul;
     27
     28	return mul & mul_mask(pll_hw);
     29}
     30
     31static unsigned long _get_table_rate(const struct clk_pll_table *table,
     32		unsigned int val)
     33{
     34	const struct clk_pll_table *clkt;
     35
     36	for (clkt = table; clkt->rate; clkt++)
     37		if (clkt->val == val)
     38			return clkt->rate;
     39
     40	return 0;
     41}
     42
     43static const struct clk_pll_table *_get_pll_table(
     44		const struct clk_pll_table *table, unsigned long rate)
     45{
     46	const struct clk_pll_table *clkt;
     47
     48	for (clkt = table; clkt->rate; clkt++) {
     49		if (clkt->rate == rate) {
     50			table = clkt;
     51			break;
     52		} else if (clkt->rate < rate)
     53			table = clkt;
     54	}
     55
     56	return table;
     57}
     58
     59static long owl_pll_round_rate(struct clk_hw *hw, unsigned long rate,
     60		unsigned long *parent_rate)
     61{
     62	struct owl_pll *pll = hw_to_owl_pll(hw);
     63	struct owl_pll_hw *pll_hw = &pll->pll_hw;
     64	const struct clk_pll_table *clkt;
     65	u32 mul;
     66
     67	if (pll_hw->table) {
     68		clkt = _get_pll_table(pll_hw->table, rate);
     69		return clkt->rate;
     70	}
     71
     72	/* fixed frequency */
     73	if (pll_hw->width == 0)
     74		return pll_hw->bfreq;
     75
     76	mul = owl_pll_calculate_mul(pll_hw, rate);
     77
     78	return pll_hw->bfreq * mul;
     79}
     80
     81static unsigned long owl_pll_recalc_rate(struct clk_hw *hw,
     82		unsigned long parent_rate)
     83{
     84	struct owl_pll *pll = hw_to_owl_pll(hw);
     85	struct owl_pll_hw *pll_hw = &pll->pll_hw;
     86	const struct owl_clk_common *common = &pll->common;
     87	u32 val;
     88
     89	if (pll_hw->table) {
     90		regmap_read(common->regmap, pll_hw->reg, &val);
     91
     92		val = val >> pll_hw->shift;
     93		val &= mul_mask(pll_hw);
     94
     95		return _get_table_rate(pll_hw->table, val);
     96	}
     97
     98	/* fixed frequency */
     99	if (pll_hw->width == 0)
    100		return pll_hw->bfreq;
    101
    102	regmap_read(common->regmap, pll_hw->reg, &val);
    103
    104	val = val >> pll_hw->shift;
    105	val &= mul_mask(pll_hw);
    106
    107	return pll_hw->bfreq * val;
    108}
    109
    110static int owl_pll_is_enabled(struct clk_hw *hw)
    111{
    112	struct owl_pll *pll = hw_to_owl_pll(hw);
    113	struct owl_pll_hw *pll_hw = &pll->pll_hw;
    114	const struct owl_clk_common *common = &pll->common;
    115	u32 reg;
    116
    117	regmap_read(common->regmap, pll_hw->reg, &reg);
    118
    119	return !!(reg & BIT(pll_hw->bit_idx));
    120}
    121
    122static void owl_pll_set(const struct owl_clk_common *common,
    123		       const struct owl_pll_hw *pll_hw, bool enable)
    124{
    125	u32 reg;
    126
    127	regmap_read(common->regmap, pll_hw->reg, &reg);
    128
    129	if (enable)
    130		reg |= BIT(pll_hw->bit_idx);
    131	else
    132		reg &= ~BIT(pll_hw->bit_idx);
    133
    134	regmap_write(common->regmap, pll_hw->reg, reg);
    135}
    136
    137static int owl_pll_enable(struct clk_hw *hw)
    138{
    139	struct owl_pll *pll = hw_to_owl_pll(hw);
    140	const struct owl_clk_common *common = &pll->common;
    141
    142	owl_pll_set(common, &pll->pll_hw, true);
    143
    144	return 0;
    145}
    146
    147static void owl_pll_disable(struct clk_hw *hw)
    148{
    149	struct owl_pll *pll = hw_to_owl_pll(hw);
    150	const struct owl_clk_common *common = &pll->common;
    151
    152	owl_pll_set(common, &pll->pll_hw, false);
    153}
    154
    155static int owl_pll_set_rate(struct clk_hw *hw, unsigned long rate,
    156		unsigned long parent_rate)
    157{
    158	struct owl_pll *pll = hw_to_owl_pll(hw);
    159	struct owl_pll_hw *pll_hw = &pll->pll_hw;
    160	const struct owl_clk_common *common = &pll->common;
    161	const struct clk_pll_table *clkt;
    162	u32 val, reg;
    163
    164	/* fixed frequency */
    165	if (pll_hw->width == 0)
    166		return 0;
    167
    168	if (pll_hw->table) {
    169		clkt = _get_pll_table(pll_hw->table, rate);
    170		val = clkt->val;
    171	} else {
    172		val = owl_pll_calculate_mul(pll_hw, rate);
    173	}
    174
    175	regmap_read(common->regmap, pll_hw->reg, &reg);
    176
    177	reg &= ~mul_mask(pll_hw);
    178	reg |= val << pll_hw->shift;
    179
    180	regmap_write(common->regmap, pll_hw->reg, reg);
    181
    182	udelay(pll_hw->delay);
    183
    184	return 0;
    185}
    186
    187const struct clk_ops owl_pll_ops = {
    188	.enable = owl_pll_enable,
    189	.disable = owl_pll_disable,
    190	.is_enabled = owl_pll_is_enabled,
    191	.round_rate = owl_pll_round_rate,
    192	.recalc_rate = owl_pll_recalc_rate,
    193	.set_rate = owl_pll_set_rate,
    194};