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

composite.c (6757B)


      1/*
      2 * TI composite clock support
      3 *
      4 * Copyright (C) 2013 Texas Instruments, Inc.
      5 *
      6 * Tero Kristo <t-kristo@ti.com>
      7 *
      8 * This program is free software; you can redistribute it and/or modify
      9 * it under the terms of the GNU General Public License version 2 as
     10 * published by the Free Software Foundation.
     11 *
     12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
     13 * kind, whether express or implied; without even the implied warranty
     14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16 */
     17
     18#include <linux/clk-provider.h>
     19#include <linux/slab.h>
     20#include <linux/io.h>
     21#include <linux/of.h>
     22#include <linux/of_address.h>
     23#include <linux/clk/ti.h>
     24#include <linux/list.h>
     25
     26#include "clock.h"
     27
     28#undef pr_fmt
     29#define pr_fmt(fmt) "%s: " fmt, __func__
     30
     31static unsigned long ti_composite_recalc_rate(struct clk_hw *hw,
     32					      unsigned long parent_rate)
     33{
     34	return ti_clk_divider_ops.recalc_rate(hw, parent_rate);
     35}
     36
     37static long ti_composite_round_rate(struct clk_hw *hw, unsigned long rate,
     38				    unsigned long *prate)
     39{
     40	return -EINVAL;
     41}
     42
     43static int ti_composite_set_rate(struct clk_hw *hw, unsigned long rate,
     44				 unsigned long parent_rate)
     45{
     46	return -EINVAL;
     47}
     48
     49static const struct clk_ops ti_composite_divider_ops = {
     50	.recalc_rate	= &ti_composite_recalc_rate,
     51	.round_rate	= &ti_composite_round_rate,
     52	.set_rate	= &ti_composite_set_rate,
     53};
     54
     55static const struct clk_ops ti_composite_gate_ops = {
     56	.enable		= &omap2_dflt_clk_enable,
     57	.disable	= &omap2_dflt_clk_disable,
     58	.is_enabled	= &omap2_dflt_clk_is_enabled,
     59};
     60
     61struct component_clk {
     62	int num_parents;
     63	const char **parent_names;
     64	struct device_node *node;
     65	int type;
     66	struct clk_hw *hw;
     67	struct list_head link;
     68};
     69
     70static const char * const component_clk_types[] __initconst = {
     71	"gate", "divider", "mux"
     72};
     73
     74static LIST_HEAD(component_clks);
     75
     76static struct device_node *_get_component_node(struct device_node *node, int i)
     77{
     78	int rc;
     79	struct of_phandle_args clkspec;
     80
     81	rc = of_parse_phandle_with_args(node, "clocks", "#clock-cells", i,
     82					&clkspec);
     83	if (rc)
     84		return NULL;
     85
     86	return clkspec.np;
     87}
     88
     89static struct component_clk *_lookup_component(struct device_node *node)
     90{
     91	struct component_clk *comp;
     92
     93	list_for_each_entry(comp, &component_clks, link) {
     94		if (comp->node == node)
     95			return comp;
     96	}
     97	return NULL;
     98}
     99
    100struct clk_hw_omap_comp {
    101	struct clk_hw hw;
    102	struct device_node *comp_nodes[CLK_COMPONENT_TYPE_MAX];
    103	struct component_clk *comp_clks[CLK_COMPONENT_TYPE_MAX];
    104};
    105
    106static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx)
    107{
    108	if (!clk)
    109		return NULL;
    110
    111	if (!clk->comp_clks[idx])
    112		return NULL;
    113
    114	return clk->comp_clks[idx]->hw;
    115}
    116
    117#define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw)
    118
    119static void __init _register_composite(void *user,
    120				       struct device_node *node)
    121{
    122	struct clk_hw *hw = user;
    123	struct clk *clk;
    124	struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw);
    125	struct component_clk *comp;
    126	int num_parents = 0;
    127	const char **parent_names = NULL;
    128	const char *name;
    129	int i;
    130	int ret;
    131
    132	/* Check for presence of each component clock */
    133	for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) {
    134		if (!cclk->comp_nodes[i])
    135			continue;
    136
    137		comp = _lookup_component(cclk->comp_nodes[i]);
    138		if (!comp) {
    139			pr_debug("component %s not ready for %pOFn, retry\n",
    140				 cclk->comp_nodes[i]->name, node);
    141			if (!ti_clk_retry_init(node, hw,
    142					       _register_composite))
    143				return;
    144
    145			goto cleanup;
    146		}
    147		if (cclk->comp_clks[comp->type] != NULL) {
    148			pr_err("duplicate component types for %pOFn (%s)!\n",
    149			       node, component_clk_types[comp->type]);
    150			goto cleanup;
    151		}
    152
    153		cclk->comp_clks[comp->type] = comp;
    154
    155		/* Mark this node as found */
    156		cclk->comp_nodes[i] = NULL;
    157	}
    158
    159	/* All components exists, proceed with registration */
    160	for (i = CLK_COMPONENT_TYPE_MAX - 1; i >= 0; i--) {
    161		comp = cclk->comp_clks[i];
    162		if (!comp)
    163			continue;
    164		if (comp->num_parents) {
    165			num_parents = comp->num_parents;
    166			parent_names = comp->parent_names;
    167			break;
    168		}
    169	}
    170
    171	if (!num_parents) {
    172		pr_err("%s: no parents found for %pOFn!\n", __func__, node);
    173		goto cleanup;
    174	}
    175
    176	name = ti_dt_clk_name(node);
    177	clk = clk_register_composite(NULL, name,
    178				     parent_names, num_parents,
    179				     _get_hw(cclk, CLK_COMPONENT_TYPE_MUX),
    180				     &ti_clk_mux_ops,
    181				     _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER),
    182				     &ti_composite_divider_ops,
    183				     _get_hw(cclk, CLK_COMPONENT_TYPE_GATE),
    184				     &ti_composite_gate_ops, 0);
    185
    186	if (!IS_ERR(clk)) {
    187		ret = ti_clk_add_alias(NULL, clk, name);
    188		if (ret) {
    189			clk_unregister(clk);
    190			goto cleanup;
    191		}
    192		of_clk_add_provider(node, of_clk_src_simple_get, clk);
    193	}
    194
    195cleanup:
    196	/* Free component clock list entries */
    197	for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) {
    198		if (!cclk->comp_clks[i])
    199			continue;
    200		list_del(&cclk->comp_clks[i]->link);
    201		kfree(cclk->comp_clks[i]->parent_names);
    202		kfree(cclk->comp_clks[i]);
    203	}
    204
    205	kfree(cclk);
    206}
    207
    208static void __init of_ti_composite_clk_setup(struct device_node *node)
    209{
    210	unsigned int num_clks;
    211	int i;
    212	struct clk_hw_omap_comp *cclk;
    213
    214	/* Number of component clocks to be put inside this clock */
    215	num_clks = of_clk_get_parent_count(node);
    216
    217	if (!num_clks) {
    218		pr_err("composite clk %pOFn must have component(s)\n", node);
    219		return;
    220	}
    221
    222	cclk = kzalloc(sizeof(*cclk), GFP_KERNEL);
    223	if (!cclk)
    224		return;
    225
    226	/* Get device node pointers for each component clock */
    227	for (i = 0; i < num_clks; i++)
    228		cclk->comp_nodes[i] = _get_component_node(node, i);
    229
    230	_register_composite(&cclk->hw, node);
    231}
    232CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock",
    233	       of_ti_composite_clk_setup);
    234
    235/**
    236 * ti_clk_add_component - add a component clock to the pool
    237 * @node: device node of the component clock
    238 * @hw: hardware clock definition for the component clock
    239 * @type: type of the component clock
    240 *
    241 * Adds a component clock to the list of available components, so that
    242 * it can be registered by a composite clock.
    243 */
    244int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw,
    245				int type)
    246{
    247	unsigned int num_parents;
    248	const char **parent_names;
    249	struct component_clk *clk;
    250
    251	num_parents = of_clk_get_parent_count(node);
    252
    253	if (!num_parents) {
    254		pr_err("component-clock %pOFn must have parent(s)\n", node);
    255		return -EINVAL;
    256	}
    257
    258	parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
    259	if (!parent_names)
    260		return -ENOMEM;
    261
    262	of_clk_parent_fill(node, parent_names, num_parents);
    263
    264	clk = kzalloc(sizeof(*clk), GFP_KERNEL);
    265	if (!clk) {
    266		kfree(parent_names);
    267		return -ENOMEM;
    268	}
    269
    270	clk->num_parents = num_parents;
    271	clk->parent_names = parent_names;
    272	clk->hw = hw;
    273	clk->node = node;
    274	clk->type = type;
    275	list_add(&clk->link, &component_clks);
    276
    277	return 0;
    278}