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-uniphier-cpugear.c (2612B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2016 Socionext Inc.
      4 *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
      5 */
      6
      7#include <linux/clk-provider.h>
      8#include <linux/device.h>
      9#include <linux/regmap.h>
     10
     11#include "clk-uniphier.h"
     12
     13#define UNIPHIER_CLK_CPUGEAR_STAT	0	/* status */
     14#define UNIPHIER_CLK_CPUGEAR_SET	4	/* set */
     15#define UNIPHIER_CLK_CPUGEAR_UPD	8	/* update */
     16#define   UNIPHIER_CLK_CPUGEAR_UPD_BIT	BIT(0)
     17
     18struct uniphier_clk_cpugear {
     19	struct clk_hw hw;
     20	struct regmap *regmap;
     21	unsigned int regbase;
     22	unsigned int mask;
     23};
     24
     25#define to_uniphier_clk_cpugear(_hw) \
     26			container_of(_hw, struct uniphier_clk_cpugear, hw)
     27
     28static int uniphier_clk_cpugear_set_parent(struct clk_hw *hw, u8 index)
     29{
     30	struct uniphier_clk_cpugear *gear = to_uniphier_clk_cpugear(hw);
     31	int ret;
     32	unsigned int val;
     33
     34	ret = regmap_write_bits(gear->regmap,
     35				gear->regbase + UNIPHIER_CLK_CPUGEAR_SET,
     36				gear->mask, index);
     37	if (ret)
     38		return ret;
     39
     40	ret = regmap_write_bits(gear->regmap,
     41				gear->regbase + UNIPHIER_CLK_CPUGEAR_UPD,
     42				UNIPHIER_CLK_CPUGEAR_UPD_BIT,
     43				UNIPHIER_CLK_CPUGEAR_UPD_BIT);
     44	if (ret)
     45		return ret;
     46
     47	return regmap_read_poll_timeout(gear->regmap,
     48				gear->regbase + UNIPHIER_CLK_CPUGEAR_UPD,
     49				val, !(val & UNIPHIER_CLK_CPUGEAR_UPD_BIT),
     50				0, 1);
     51}
     52
     53static u8 uniphier_clk_cpugear_get_parent(struct clk_hw *hw)
     54{
     55	struct uniphier_clk_cpugear *gear = to_uniphier_clk_cpugear(hw);
     56	int num_parents = clk_hw_get_num_parents(hw);
     57	int ret;
     58	unsigned int val;
     59
     60	ret = regmap_read(gear->regmap,
     61			  gear->regbase + UNIPHIER_CLK_CPUGEAR_STAT, &val);
     62	if (ret)
     63		return ret;
     64
     65	val &= gear->mask;
     66
     67	return val < num_parents ? val : -EINVAL;
     68}
     69
     70static const struct clk_ops uniphier_clk_cpugear_ops = {
     71	.determine_rate = __clk_mux_determine_rate,
     72	.set_parent = uniphier_clk_cpugear_set_parent,
     73	.get_parent = uniphier_clk_cpugear_get_parent,
     74};
     75
     76struct clk_hw *uniphier_clk_register_cpugear(struct device *dev,
     77					 struct regmap *regmap,
     78					 const char *name,
     79				const struct uniphier_clk_cpugear_data *data)
     80{
     81	struct uniphier_clk_cpugear *gear;
     82	struct clk_init_data init;
     83	int ret;
     84
     85	gear = devm_kzalloc(dev, sizeof(*gear), GFP_KERNEL);
     86	if (!gear)
     87		return ERR_PTR(-ENOMEM);
     88
     89	init.name = name;
     90	init.ops = &uniphier_clk_cpugear_ops;
     91	init.flags = CLK_SET_RATE_PARENT;
     92	init.parent_names = data->parent_names;
     93	init.num_parents = data->num_parents;
     94
     95	gear->regmap = regmap;
     96	gear->regbase = data->regbase;
     97	gear->mask = data->mask;
     98	gear->hw.init = &init;
     99
    100	ret = devm_clk_hw_register(dev, &gear->hw);
    101	if (ret)
    102		return ERR_PTR(ret);
    103
    104	return &gear->hw;
    105}