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-cpumux.c (3573B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2015 Linaro Ltd.
      4 * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
      5 */
      6
      7#include <linux/clk-provider.h>
      8#include <linux/container_of.h>
      9#include <linux/err.h>
     10#include <linux/mfd/syscon.h>
     11#include <linux/module.h>
     12#include <linux/regmap.h>
     13#include <linux/slab.h>
     14
     15#include "clk-mtk.h"
     16#include "clk-cpumux.h"
     17
     18struct mtk_clk_cpumux {
     19	struct clk_hw	hw;
     20	struct regmap	*regmap;
     21	u32		reg;
     22	u32		mask;
     23	u8		shift;
     24};
     25
     26static inline struct mtk_clk_cpumux *to_mtk_clk_cpumux(struct clk_hw *_hw)
     27{
     28	return container_of(_hw, struct mtk_clk_cpumux, hw);
     29}
     30
     31static u8 clk_cpumux_get_parent(struct clk_hw *hw)
     32{
     33	struct mtk_clk_cpumux *mux = to_mtk_clk_cpumux(hw);
     34	unsigned int val;
     35
     36	regmap_read(mux->regmap, mux->reg, &val);
     37
     38	val >>= mux->shift;
     39	val &= mux->mask;
     40
     41	return val;
     42}
     43
     44static int clk_cpumux_set_parent(struct clk_hw *hw, u8 index)
     45{
     46	struct mtk_clk_cpumux *mux = to_mtk_clk_cpumux(hw);
     47	u32 mask, val;
     48
     49	val = index << mux->shift;
     50	mask = mux->mask << mux->shift;
     51
     52	return regmap_update_bits(mux->regmap, mux->reg, mask, val);
     53}
     54
     55static const struct clk_ops clk_cpumux_ops = {
     56	.get_parent = clk_cpumux_get_parent,
     57	.set_parent = clk_cpumux_set_parent,
     58};
     59
     60static struct clk_hw *
     61mtk_clk_register_cpumux(const struct mtk_composite *mux,
     62			struct regmap *regmap)
     63{
     64	struct mtk_clk_cpumux *cpumux;
     65	int ret;
     66	struct clk_init_data init;
     67
     68	cpumux = kzalloc(sizeof(*cpumux), GFP_KERNEL);
     69	if (!cpumux)
     70		return ERR_PTR(-ENOMEM);
     71
     72	init.name = mux->name;
     73	init.ops = &clk_cpumux_ops;
     74	init.parent_names = mux->parent_names;
     75	init.num_parents = mux->num_parents;
     76	init.flags = mux->flags;
     77
     78	cpumux->reg = mux->mux_reg;
     79	cpumux->shift = mux->mux_shift;
     80	cpumux->mask = BIT(mux->mux_width) - 1;
     81	cpumux->regmap = regmap;
     82	cpumux->hw.init = &init;
     83
     84	ret = clk_hw_register(NULL, &cpumux->hw);
     85	if (ret) {
     86		kfree(cpumux);
     87		return ERR_PTR(ret);
     88	}
     89
     90	return &cpumux->hw;
     91}
     92
     93static void mtk_clk_unregister_cpumux(struct clk_hw *hw)
     94{
     95	struct mtk_clk_cpumux *cpumux;
     96	if (!hw)
     97		return;
     98
     99	cpumux = to_mtk_clk_cpumux(hw);
    100
    101	clk_hw_unregister(hw);
    102	kfree(cpumux);
    103}
    104
    105int mtk_clk_register_cpumuxes(struct device_node *node,
    106			      const struct mtk_composite *clks, int num,
    107			      struct clk_hw_onecell_data *clk_data)
    108{
    109	int i;
    110	struct clk_hw *hw;
    111	struct regmap *regmap;
    112
    113	regmap = device_node_to_regmap(node);
    114	if (IS_ERR(regmap)) {
    115		pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
    116		return PTR_ERR(regmap);
    117	}
    118
    119	for (i = 0; i < num; i++) {
    120		const struct mtk_composite *mux = &clks[i];
    121
    122		if (!IS_ERR_OR_NULL(clk_data->hws[mux->id])) {
    123			pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
    124				node, mux->id);
    125			continue;
    126		}
    127
    128		hw = mtk_clk_register_cpumux(mux, regmap);
    129		if (IS_ERR(hw)) {
    130			pr_err("Failed to register clk %s: %pe\n", mux->name,
    131			       hw);
    132			goto err;
    133		}
    134
    135		clk_data->hws[mux->id] = hw;
    136	}
    137
    138	return 0;
    139
    140err:
    141	while (--i >= 0) {
    142		const struct mtk_composite *mux = &clks[i];
    143
    144		if (IS_ERR_OR_NULL(clk_data->hws[mux->id]))
    145			continue;
    146
    147		mtk_clk_unregister_cpumux(clk_data->hws[mux->id]);
    148		clk_data->hws[mux->id] = ERR_PTR(-ENOENT);
    149	}
    150
    151	return PTR_ERR(hw);
    152}
    153
    154void mtk_clk_unregister_cpumuxes(const struct mtk_composite *clks, int num,
    155				 struct clk_hw_onecell_data *clk_data)
    156{
    157	int i;
    158
    159	for (i = num; i > 0; i--) {
    160		const struct mtk_composite *mux = &clks[i - 1];
    161
    162		if (IS_ERR_OR_NULL(clk_data->hws[mux->id]))
    163			continue;
    164
    165		mtk_clk_unregister_cpumux(clk_data->hws[mux->id]);
    166		clk_data->hws[mux->id] = ERR_PTR(-ENOENT);
    167	}
    168}
    169
    170MODULE_LICENSE("GPL");