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-mux-zynqmp.c (4303B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Zynq UltraScale+ MPSoC mux
      4 *
      5 *  Copyright (C) 2016-2018 Xilinx
      6 */
      7
      8#include <linux/clk-provider.h>
      9#include <linux/slab.h>
     10#include "clk-zynqmp.h"
     11
     12/*
     13 * DOC: basic adjustable multiplexer clock that cannot gate
     14 *
     15 * Traits of this clock:
     16 * prepare - clk_prepare only ensures that parents are prepared
     17 * enable - clk_enable only ensures that parents are enabled
     18 * rate - rate is only affected by parent switching.  No clk_set_rate support
     19 * parent - parent is adjustable through clk_set_parent
     20 */
     21
     22/**
     23 * struct zynqmp_clk_mux - multiplexer clock
     24 *
     25 * @hw:		handle between common and hardware-specific interfaces
     26 * @flags:	hardware-specific flags
     27 * @clk_id:	Id of clock
     28 */
     29struct zynqmp_clk_mux {
     30	struct clk_hw hw;
     31	u8 flags;
     32	u32 clk_id;
     33};
     34
     35#define to_zynqmp_clk_mux(_hw) container_of(_hw, struct zynqmp_clk_mux, hw)
     36
     37/**
     38 * zynqmp_clk_mux_get_parent() - Get parent of clock
     39 * @hw:		handle between common and hardware-specific interfaces
     40 *
     41 * Return: Parent index on success or number of parents in case of error
     42 */
     43static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw)
     44{
     45	struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
     46	const char *clk_name = clk_hw_get_name(hw);
     47	u32 clk_id = mux->clk_id;
     48	u32 val;
     49	int ret;
     50
     51	ret = zynqmp_pm_clock_getparent(clk_id, &val);
     52
     53	if (ret) {
     54		pr_debug("%s() getparent failed for clock: %s, ret = %d\n",
     55			 __func__, clk_name, ret);
     56		/*
     57		 * clk_core_get_parent_by_index() takes num_parents as incorrect
     58		 * index which is exactly what I want to return here
     59		 */
     60		return clk_hw_get_num_parents(hw);
     61	}
     62
     63	return val;
     64}
     65
     66/**
     67 * zynqmp_clk_mux_set_parent() - Set parent of clock
     68 * @hw:		handle between common and hardware-specific interfaces
     69 * @index:	Parent index
     70 *
     71 * Return: 0 on success else error+reason
     72 */
     73static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index)
     74{
     75	struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
     76	const char *clk_name = clk_hw_get_name(hw);
     77	u32 clk_id = mux->clk_id;
     78	int ret;
     79
     80	ret = zynqmp_pm_clock_setparent(clk_id, index);
     81
     82	if (ret)
     83		pr_debug("%s() set parent failed for clock: %s, ret = %d\n",
     84			 __func__, clk_name, ret);
     85
     86	return ret;
     87}
     88
     89static const struct clk_ops zynqmp_clk_mux_ops = {
     90	.get_parent = zynqmp_clk_mux_get_parent,
     91	.set_parent = zynqmp_clk_mux_set_parent,
     92	.determine_rate = __clk_mux_determine_rate,
     93};
     94
     95static const struct clk_ops zynqmp_clk_mux_ro_ops = {
     96	.get_parent = zynqmp_clk_mux_get_parent,
     97};
     98
     99static inline unsigned long zynqmp_clk_map_mux_ccf_flags(
    100				       const u32 zynqmp_type_flag)
    101{
    102	unsigned long ccf_flag = 0;
    103
    104	if (zynqmp_type_flag & ZYNQMP_CLK_MUX_INDEX_ONE)
    105		ccf_flag |= CLK_MUX_INDEX_ONE;
    106	if (zynqmp_type_flag & ZYNQMP_CLK_MUX_INDEX_BIT)
    107		ccf_flag |= CLK_MUX_INDEX_BIT;
    108	if (zynqmp_type_flag & ZYNQMP_CLK_MUX_HIWORD_MASK)
    109		ccf_flag |= CLK_MUX_HIWORD_MASK;
    110	if (zynqmp_type_flag & ZYNQMP_CLK_MUX_READ_ONLY)
    111		ccf_flag |= CLK_MUX_READ_ONLY;
    112	if (zynqmp_type_flag & ZYNQMP_CLK_MUX_ROUND_CLOSEST)
    113		ccf_flag |= CLK_MUX_ROUND_CLOSEST;
    114	if (zynqmp_type_flag & ZYNQMP_CLK_MUX_BIG_ENDIAN)
    115		ccf_flag |= CLK_MUX_BIG_ENDIAN;
    116
    117	return ccf_flag;
    118}
    119
    120/**
    121 * zynqmp_clk_register_mux() - Register a mux table with the clock
    122 *			       framework
    123 * @name:		Name of this clock
    124 * @clk_id:		Id of this clock
    125 * @parents:		Name of this clock's parents
    126 * @num_parents:	Number of parents
    127 * @nodes:		Clock topology node
    128 *
    129 * Return: clock hardware of the registered clock mux
    130 */
    131struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id,
    132				       const char * const *parents,
    133				       u8 num_parents,
    134				       const struct clock_topology *nodes)
    135{
    136	struct zynqmp_clk_mux *mux;
    137	struct clk_hw *hw;
    138	struct clk_init_data init;
    139	int ret;
    140
    141	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
    142	if (!mux)
    143		return ERR_PTR(-ENOMEM);
    144
    145	init.name = name;
    146	if (nodes->type_flag & CLK_MUX_READ_ONLY)
    147		init.ops = &zynqmp_clk_mux_ro_ops;
    148	else
    149		init.ops = &zynqmp_clk_mux_ops;
    150
    151	init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag);
    152
    153	init.parent_names = parents;
    154	init.num_parents = num_parents;
    155	mux->flags = zynqmp_clk_map_mux_ccf_flags(nodes->type_flag);
    156	mux->hw.init = &init;
    157	mux->clk_id = clk_id;
    158
    159	hw = &mux->hw;
    160	ret = clk_hw_register(NULL, hw);
    161	if (ret) {
    162		kfree(mux);
    163		hw = ERR_PTR(ret);
    164	}
    165
    166	return hw;
    167}