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-a10-pll2.c (5280B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2013 Emilio López
      4 * Emilio López <emilio@elopez.com.ar>
      5 *
      6 * Copyright 2015 Maxime Ripard
      7 * Maxime Ripard <maxime.ripard@free-electrons.com>
      8 */
      9
     10#include <linux/clk-provider.h>
     11#include <linux/io.h>
     12#include <linux/of.h>
     13#include <linux/of_address.h>
     14#include <linux/slab.h>
     15
     16#include <dt-bindings/clock/sun4i-a10-pll2.h>
     17
     18#define SUN4I_PLL2_ENABLE		31
     19
     20#define SUN4I_PLL2_PRE_DIV_SHIFT	0
     21#define SUN4I_PLL2_PRE_DIV_WIDTH	5
     22#define SUN4I_PLL2_PRE_DIV_MASK		GENMASK(SUN4I_PLL2_PRE_DIV_WIDTH - 1, 0)
     23
     24#define SUN4I_PLL2_N_SHIFT		8
     25#define SUN4I_PLL2_N_WIDTH		7
     26#define SUN4I_PLL2_N_MASK		GENMASK(SUN4I_PLL2_N_WIDTH - 1, 0)
     27
     28#define SUN4I_PLL2_POST_DIV_SHIFT	26
     29#define SUN4I_PLL2_POST_DIV_WIDTH	4
     30#define SUN4I_PLL2_POST_DIV_MASK	GENMASK(SUN4I_PLL2_POST_DIV_WIDTH - 1, 0)
     31
     32#define SUN4I_PLL2_POST_DIV_VALUE	4
     33
     34#define SUN4I_PLL2_OUTPUTS		4
     35
     36static DEFINE_SPINLOCK(sun4i_a10_pll2_lock);
     37
     38static void __init sun4i_pll2_setup(struct device_node *node,
     39				    int post_div_offset)
     40{
     41	const char *clk_name = node->name, *parent;
     42	struct clk **clks, *base_clk, *prediv_clk;
     43	struct clk_onecell_data *clk_data;
     44	struct clk_multiplier *mult;
     45	struct clk_gate *gate;
     46	void __iomem *reg;
     47	u32 val;
     48
     49	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
     50	if (IS_ERR(reg))
     51		return;
     52
     53	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
     54	if (!clk_data)
     55		goto err_unmap;
     56
     57	clks = kcalloc(SUN4I_PLL2_OUTPUTS, sizeof(struct clk *), GFP_KERNEL);
     58	if (!clks)
     59		goto err_free_data;
     60
     61	parent = of_clk_get_parent_name(node, 0);
     62	prediv_clk = clk_register_divider(NULL, "pll2-prediv",
     63					  parent, 0, reg,
     64					  SUN4I_PLL2_PRE_DIV_SHIFT,
     65					  SUN4I_PLL2_PRE_DIV_WIDTH,
     66					  CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
     67					  &sun4i_a10_pll2_lock);
     68	if (IS_ERR(prediv_clk)) {
     69		pr_err("Couldn't register the prediv clock\n");
     70		goto err_free_array;
     71	}
     72
     73	/* Setup the gate part of the PLL2 */
     74	gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
     75	if (!gate)
     76		goto err_unregister_prediv;
     77
     78	gate->reg = reg;
     79	gate->bit_idx = SUN4I_PLL2_ENABLE;
     80	gate->lock = &sun4i_a10_pll2_lock;
     81
     82	/* Setup the multiplier part of the PLL2 */
     83	mult = kzalloc(sizeof(struct clk_multiplier), GFP_KERNEL);
     84	if (!mult)
     85		goto err_free_gate;
     86
     87	mult->reg = reg;
     88	mult->shift = SUN4I_PLL2_N_SHIFT;
     89	mult->width = 7;
     90	mult->flags = CLK_MULTIPLIER_ZERO_BYPASS |
     91			CLK_MULTIPLIER_ROUND_CLOSEST;
     92	mult->lock = &sun4i_a10_pll2_lock;
     93
     94	parent = __clk_get_name(prediv_clk);
     95	base_clk = clk_register_composite(NULL, "pll2-base",
     96					  &parent, 1,
     97					  NULL, NULL,
     98					  &mult->hw, &clk_multiplier_ops,
     99					  &gate->hw, &clk_gate_ops,
    100					  CLK_SET_RATE_PARENT);
    101	if (IS_ERR(base_clk)) {
    102		pr_err("Couldn't register the base multiplier clock\n");
    103		goto err_free_multiplier;
    104	}
    105
    106	parent = __clk_get_name(base_clk);
    107
    108	/*
    109	 * PLL2-1x
    110	 *
    111	 * This is supposed to have a post divider, but we won't need
    112	 * to use it, we just need to initialise it to 4, and use a
    113	 * fixed divider.
    114	 */
    115	val = readl(reg);
    116	val &= ~(SUN4I_PLL2_POST_DIV_MASK << SUN4I_PLL2_POST_DIV_SHIFT);
    117	val |= (SUN4I_PLL2_POST_DIV_VALUE - post_div_offset) << SUN4I_PLL2_POST_DIV_SHIFT;
    118	writel(val, reg);
    119
    120	of_property_read_string_index(node, "clock-output-names",
    121				      SUN4I_A10_PLL2_1X, &clk_name);
    122	clks[SUN4I_A10_PLL2_1X] = clk_register_fixed_factor(NULL, clk_name,
    123							    parent,
    124							    CLK_SET_RATE_PARENT,
    125							    1,
    126							    SUN4I_PLL2_POST_DIV_VALUE);
    127	WARN_ON(IS_ERR(clks[SUN4I_A10_PLL2_1X]));
    128
    129	/*
    130	 * PLL2-2x
    131	 *
    132	 * This clock doesn't use the post divider, and really is just
    133	 * a fixed divider from the PLL2 base clock.
    134	 */
    135	of_property_read_string_index(node, "clock-output-names",
    136				      SUN4I_A10_PLL2_2X, &clk_name);
    137	clks[SUN4I_A10_PLL2_2X] = clk_register_fixed_factor(NULL, clk_name,
    138							    parent,
    139							    CLK_SET_RATE_PARENT,
    140							    1, 2);
    141	WARN_ON(IS_ERR(clks[SUN4I_A10_PLL2_2X]));
    142
    143	/* PLL2-4x */
    144	of_property_read_string_index(node, "clock-output-names",
    145				      SUN4I_A10_PLL2_4X, &clk_name);
    146	clks[SUN4I_A10_PLL2_4X] = clk_register_fixed_factor(NULL, clk_name,
    147							    parent,
    148							    CLK_SET_RATE_PARENT,
    149							    1, 1);
    150	WARN_ON(IS_ERR(clks[SUN4I_A10_PLL2_4X]));
    151
    152	/* PLL2-8x */
    153	of_property_read_string_index(node, "clock-output-names",
    154				      SUN4I_A10_PLL2_8X, &clk_name);
    155	clks[SUN4I_A10_PLL2_8X] = clk_register_fixed_factor(NULL, clk_name,
    156							    parent,
    157							    CLK_SET_RATE_PARENT,
    158							    2, 1);
    159	WARN_ON(IS_ERR(clks[SUN4I_A10_PLL2_8X]));
    160
    161	clk_data->clks = clks;
    162	clk_data->clk_num = SUN4I_PLL2_OUTPUTS;
    163	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
    164
    165	return;
    166
    167err_free_multiplier:
    168	kfree(mult);
    169err_free_gate:
    170	kfree(gate);
    171err_unregister_prediv:
    172	clk_unregister_divider(prediv_clk);
    173err_free_array:
    174	kfree(clks);
    175err_free_data:
    176	kfree(clk_data);
    177err_unmap:
    178	iounmap(reg);
    179}
    180
    181static void __init sun4i_a10_pll2_setup(struct device_node *node)
    182{
    183	sun4i_pll2_setup(node, 0);
    184}
    185
    186CLK_OF_DECLARE(sun4i_a10_pll2, "allwinner,sun4i-a10-pll2-clk",
    187	       sun4i_a10_pll2_setup);
    188
    189static void __init sun5i_a13_pll2_setup(struct device_node *node)
    190{
    191	sun4i_pll2_setup(node, 1);
    192}
    193
    194CLK_OF_DECLARE(sun5i_a13_pll2, "allwinner,sun5i-a13-pll2-clk",
    195	       sun5i_a13_pll2_setup);