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-periph.c (6691B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
      4 */
      5
      6#include <linux/clk.h>
      7#include <linux/clk-provider.h>
      8#include <linux/export.h>
      9#include <linux/slab.h>
     10#include <linux/err.h>
     11
     12#include "clk.h"
     13
     14static u8 clk_periph_get_parent(struct clk_hw *hw)
     15{
     16	struct tegra_clk_periph *periph = to_clk_periph(hw);
     17	const struct clk_ops *mux_ops = periph->mux_ops;
     18	struct clk_hw *mux_hw = &periph->mux.hw;
     19
     20	__clk_hw_set_clk(mux_hw, hw);
     21
     22	return mux_ops->get_parent(mux_hw);
     23}
     24
     25static int clk_periph_set_parent(struct clk_hw *hw, u8 index)
     26{
     27	struct tegra_clk_periph *periph = to_clk_periph(hw);
     28	const struct clk_ops *mux_ops = periph->mux_ops;
     29	struct clk_hw *mux_hw = &periph->mux.hw;
     30
     31	__clk_hw_set_clk(mux_hw, hw);
     32
     33	return mux_ops->set_parent(mux_hw, index);
     34}
     35
     36static unsigned long clk_periph_recalc_rate(struct clk_hw *hw,
     37					    unsigned long parent_rate)
     38{
     39	struct tegra_clk_periph *periph = to_clk_periph(hw);
     40	const struct clk_ops *div_ops = periph->div_ops;
     41	struct clk_hw *div_hw = &periph->divider.hw;
     42
     43	__clk_hw_set_clk(div_hw, hw);
     44
     45	return div_ops->recalc_rate(div_hw, parent_rate);
     46}
     47
     48static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate,
     49				  unsigned long *prate)
     50{
     51	struct tegra_clk_periph *periph = to_clk_periph(hw);
     52	const struct clk_ops *div_ops = periph->div_ops;
     53	struct clk_hw *div_hw = &periph->divider.hw;
     54
     55	__clk_hw_set_clk(div_hw, hw);
     56
     57	return div_ops->round_rate(div_hw, rate, prate);
     58}
     59
     60static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate,
     61			       unsigned long parent_rate)
     62{
     63	struct tegra_clk_periph *periph = to_clk_periph(hw);
     64	const struct clk_ops *div_ops = periph->div_ops;
     65	struct clk_hw *div_hw = &periph->divider.hw;
     66
     67	__clk_hw_set_clk(div_hw, hw);
     68
     69	return div_ops->set_rate(div_hw, rate, parent_rate);
     70}
     71
     72static int clk_periph_is_enabled(struct clk_hw *hw)
     73{
     74	struct tegra_clk_periph *periph = to_clk_periph(hw);
     75	const struct clk_ops *gate_ops = periph->gate_ops;
     76	struct clk_hw *gate_hw = &periph->gate.hw;
     77
     78	__clk_hw_set_clk(gate_hw, hw);
     79
     80	return gate_ops->is_enabled(gate_hw);
     81}
     82
     83static int clk_periph_enable(struct clk_hw *hw)
     84{
     85	struct tegra_clk_periph *periph = to_clk_periph(hw);
     86	const struct clk_ops *gate_ops = periph->gate_ops;
     87	struct clk_hw *gate_hw = &periph->gate.hw;
     88
     89	__clk_hw_set_clk(gate_hw, hw);
     90
     91	return gate_ops->enable(gate_hw);
     92}
     93
     94static void clk_periph_disable(struct clk_hw *hw)
     95{
     96	struct tegra_clk_periph *periph = to_clk_periph(hw);
     97	const struct clk_ops *gate_ops = periph->gate_ops;
     98	struct clk_hw *gate_hw = &periph->gate.hw;
     99
    100	gate_ops->disable(gate_hw);
    101}
    102
    103static void clk_periph_disable_unused(struct clk_hw *hw)
    104{
    105	struct tegra_clk_periph *periph = to_clk_periph(hw);
    106	const struct clk_ops *gate_ops = periph->gate_ops;
    107	struct clk_hw *gate_hw = &periph->gate.hw;
    108
    109	gate_ops->disable_unused(gate_hw);
    110}
    111
    112static void clk_periph_restore_context(struct clk_hw *hw)
    113{
    114	struct tegra_clk_periph *periph = to_clk_periph(hw);
    115	const struct clk_ops *div_ops = periph->div_ops;
    116	struct clk_hw *div_hw = &periph->divider.hw;
    117	int parent_id;
    118
    119	parent_id = clk_hw_get_parent_index(hw);
    120	if (WARN_ON(parent_id < 0))
    121		return;
    122
    123	if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
    124		div_ops->restore_context(div_hw);
    125
    126	clk_periph_set_parent(hw, parent_id);
    127}
    128
    129const struct clk_ops tegra_clk_periph_ops = {
    130	.get_parent = clk_periph_get_parent,
    131	.set_parent = clk_periph_set_parent,
    132	.recalc_rate = clk_periph_recalc_rate,
    133	.round_rate = clk_periph_round_rate,
    134	.set_rate = clk_periph_set_rate,
    135	.is_enabled = clk_periph_is_enabled,
    136	.enable = clk_periph_enable,
    137	.disable = clk_periph_disable,
    138	.disable_unused = clk_periph_disable_unused,
    139	.restore_context = clk_periph_restore_context,
    140};
    141
    142static const struct clk_ops tegra_clk_periph_nodiv_ops = {
    143	.get_parent = clk_periph_get_parent,
    144	.set_parent = clk_periph_set_parent,
    145	.is_enabled = clk_periph_is_enabled,
    146	.enable = clk_periph_enable,
    147	.disable = clk_periph_disable,
    148	.disable_unused = clk_periph_disable_unused,
    149	.restore_context = clk_periph_restore_context,
    150};
    151
    152static const struct clk_ops tegra_clk_periph_no_gate_ops = {
    153	.get_parent = clk_periph_get_parent,
    154	.set_parent = clk_periph_set_parent,
    155	.recalc_rate = clk_periph_recalc_rate,
    156	.round_rate = clk_periph_round_rate,
    157	.set_rate = clk_periph_set_rate,
    158	.restore_context = clk_periph_restore_context,
    159};
    160
    161static struct clk *_tegra_clk_register_periph(const char *name,
    162			const char * const *parent_names, int num_parents,
    163			struct tegra_clk_periph *periph,
    164			void __iomem *clk_base, u32 offset,
    165			unsigned long flags)
    166{
    167	struct clk *clk;
    168	struct clk_init_data init;
    169	const struct tegra_clk_periph_regs *bank;
    170	bool div = !(periph->gate.flags & TEGRA_PERIPH_NO_DIV);
    171
    172	if (periph->gate.flags & TEGRA_PERIPH_NO_DIV) {
    173		flags |= CLK_SET_RATE_PARENT;
    174		init.ops = &tegra_clk_periph_nodiv_ops;
    175	} else if (periph->gate.flags & TEGRA_PERIPH_NO_GATE)
    176		init.ops = &tegra_clk_periph_no_gate_ops;
    177	else
    178		init.ops = &tegra_clk_periph_ops;
    179
    180	init.name = name;
    181	init.flags = flags;
    182	init.parent_names = parent_names;
    183	init.num_parents = num_parents;
    184
    185	bank = get_reg_bank(periph->gate.clk_num);
    186	if (!bank)
    187		return ERR_PTR(-EINVAL);
    188
    189	/* Data in .init is copied by clk_register(), so stack variable OK */
    190	periph->hw.init = &init;
    191	periph->magic = TEGRA_CLK_PERIPH_MAGIC;
    192	periph->mux.reg = clk_base + offset;
    193	periph->divider.reg = div ? (clk_base + offset) : NULL;
    194	periph->gate.clk_base = clk_base;
    195	periph->gate.regs = bank;
    196	periph->gate.enable_refcnt = periph_clk_enb_refcnt;
    197
    198	clk = clk_register(NULL, &periph->hw);
    199	if (IS_ERR(clk))
    200		return clk;
    201
    202	periph->mux.hw.clk = clk;
    203	periph->divider.hw.clk = div ? clk : NULL;
    204	periph->gate.hw.clk = clk;
    205
    206	return clk;
    207}
    208
    209struct clk *tegra_clk_register_periph(const char *name,
    210		const char * const *parent_names, int num_parents,
    211		struct tegra_clk_periph *periph, void __iomem *clk_base,
    212		u32 offset, unsigned long flags)
    213{
    214	return _tegra_clk_register_periph(name, parent_names, num_parents,
    215			periph, clk_base, offset, flags);
    216}
    217
    218struct clk *tegra_clk_register_periph_nodiv(const char *name,
    219		const char * const *parent_names, int num_parents,
    220		struct tegra_clk_periph *periph, void __iomem *clk_base,
    221		u32 offset)
    222{
    223	periph->gate.flags |= TEGRA_PERIPH_NO_DIV;
    224	return _tegra_clk_register_periph(name, parent_names, num_parents,
    225			periph, clk_base, offset, CLK_SET_RATE_PARENT);
    226}
    227
    228struct clk *tegra_clk_register_periph_data(void __iomem *clk_base,
    229					   struct tegra_periph_init_data *init)
    230{
    231	return _tegra_clk_register_periph(init->name, init->p.parent_names,
    232					  init->num_parents, &init->periph,
    233					  clk_base, init->offset, init->flags);
    234}