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

mux.c (6980B)


      1/*
      2 * TI Multiplexer Clock
      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/err.h>
     21#include <linux/of.h>
     22#include <linux/of_address.h>
     23#include <linux/clk/ti.h>
     24#include "clock.h"
     25
     26#undef pr_fmt
     27#define pr_fmt(fmt) "%s: " fmt, __func__
     28
     29static u8 ti_clk_mux_get_parent(struct clk_hw *hw)
     30{
     31	struct clk_omap_mux *mux = to_clk_omap_mux(hw);
     32	int num_parents = clk_hw_get_num_parents(hw);
     33	u32 val;
     34
     35	/*
     36	 * FIXME need a mux-specific flag to determine if val is bitwise or
     37	 * numeric. e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges
     38	 * from 0x1 to 0x7 (index starts at one)
     39	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
     40	 * val = 0x4 really means "bit 2, index starts at bit 0"
     41	 */
     42	val = ti_clk_ll_ops->clk_readl(&mux->reg) >> mux->shift;
     43	val &= mux->mask;
     44
     45	if (mux->table) {
     46		int i;
     47
     48		for (i = 0; i < num_parents; i++)
     49			if (mux->table[i] == val)
     50				return i;
     51		return -EINVAL;
     52	}
     53
     54	if (val && (mux->flags & CLK_MUX_INDEX_BIT))
     55		val = ffs(val) - 1;
     56
     57	if (val && (mux->flags & CLK_MUX_INDEX_ONE))
     58		val--;
     59
     60	if (val >= num_parents)
     61		return -EINVAL;
     62
     63	return val;
     64}
     65
     66static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
     67{
     68	struct clk_omap_mux *mux = to_clk_omap_mux(hw);
     69	u32 val;
     70
     71	if (mux->table) {
     72		index = mux->table[index];
     73	} else {
     74		if (mux->flags & CLK_MUX_INDEX_BIT)
     75			index = (1 << ffs(index));
     76
     77		if (mux->flags & CLK_MUX_INDEX_ONE)
     78			index++;
     79	}
     80
     81	if (mux->flags & CLK_MUX_HIWORD_MASK) {
     82		val = mux->mask << (mux->shift + 16);
     83	} else {
     84		val = ti_clk_ll_ops->clk_readl(&mux->reg);
     85		val &= ~(mux->mask << mux->shift);
     86	}
     87	val |= index << mux->shift;
     88	ti_clk_ll_ops->clk_writel(val, &mux->reg);
     89	ti_clk_latch(&mux->reg, mux->latch);
     90
     91	return 0;
     92}
     93
     94/**
     95 * clk_mux_save_context - Save the parent selcted in the mux
     96 * @hw: pointer  struct clk_hw
     97 *
     98 * Save the parent mux value.
     99 */
    100static int clk_mux_save_context(struct clk_hw *hw)
    101{
    102	struct clk_omap_mux *mux = to_clk_omap_mux(hw);
    103
    104	mux->saved_parent = ti_clk_mux_get_parent(hw);
    105	return 0;
    106}
    107
    108/**
    109 * clk_mux_restore_context - Restore the parent in the mux
    110 * @hw: pointer  struct clk_hw
    111 *
    112 * Restore the saved parent mux value.
    113 */
    114static void clk_mux_restore_context(struct clk_hw *hw)
    115{
    116	struct clk_omap_mux *mux = to_clk_omap_mux(hw);
    117
    118	ti_clk_mux_set_parent(hw, mux->saved_parent);
    119}
    120
    121const struct clk_ops ti_clk_mux_ops = {
    122	.get_parent = ti_clk_mux_get_parent,
    123	.set_parent = ti_clk_mux_set_parent,
    124	.determine_rate = __clk_mux_determine_rate,
    125	.save_context = clk_mux_save_context,
    126	.restore_context = clk_mux_restore_context,
    127};
    128
    129static struct clk *_register_mux(struct device *dev, const char *name,
    130				 const char * const *parent_names,
    131				 u8 num_parents, unsigned long flags,
    132				 struct clk_omap_reg *reg, u8 shift, u32 mask,
    133				 s8 latch, u8 clk_mux_flags, u32 *table)
    134{
    135	struct clk_omap_mux *mux;
    136	struct clk *clk;
    137	struct clk_init_data init;
    138
    139	/* allocate the mux */
    140	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
    141	if (!mux)
    142		return ERR_PTR(-ENOMEM);
    143
    144	init.name = name;
    145	init.ops = &ti_clk_mux_ops;
    146	init.flags = flags;
    147	init.parent_names = parent_names;
    148	init.num_parents = num_parents;
    149
    150	/* struct clk_mux assignments */
    151	memcpy(&mux->reg, reg, sizeof(*reg));
    152	mux->shift = shift;
    153	mux->mask = mask;
    154	mux->latch = latch;
    155	mux->flags = clk_mux_flags;
    156	mux->table = table;
    157	mux->hw.init = &init;
    158
    159	clk = ti_clk_register(dev, &mux->hw, name);
    160
    161	if (IS_ERR(clk))
    162		kfree(mux);
    163
    164	return clk;
    165}
    166
    167/**
    168 * of_mux_clk_setup - Setup function for simple mux rate clock
    169 * @node: DT node for the clock
    170 *
    171 * Sets up a basic clock multiplexer.
    172 */
    173static void of_mux_clk_setup(struct device_node *node)
    174{
    175	struct clk *clk;
    176	struct clk_omap_reg reg;
    177	unsigned int num_parents;
    178	const char **parent_names;
    179	const char *name;
    180	u8 clk_mux_flags = 0;
    181	u32 mask = 0;
    182	u32 shift = 0;
    183	s32 latch = -EINVAL;
    184	u32 flags = CLK_SET_RATE_NO_REPARENT;
    185
    186	num_parents = of_clk_get_parent_count(node);
    187	if (num_parents < 2) {
    188		pr_err("mux-clock %pOFn must have parents\n", node);
    189		return;
    190	}
    191	parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
    192	if (!parent_names)
    193		goto cleanup;
    194
    195	of_clk_parent_fill(node, parent_names, num_parents);
    196
    197	if (ti_clk_get_reg_addr(node, 0, &reg))
    198		goto cleanup;
    199
    200	of_property_read_u32(node, "ti,bit-shift", &shift);
    201
    202	of_property_read_u32(node, "ti,latch-bit", &latch);
    203
    204	if (of_property_read_bool(node, "ti,index-starts-at-one"))
    205		clk_mux_flags |= CLK_MUX_INDEX_ONE;
    206
    207	if (of_property_read_bool(node, "ti,set-rate-parent"))
    208		flags |= CLK_SET_RATE_PARENT;
    209
    210	/* Generate bit-mask based on parent info */
    211	mask = num_parents;
    212	if (!(clk_mux_flags & CLK_MUX_INDEX_ONE))
    213		mask--;
    214
    215	mask = (1 << fls(mask)) - 1;
    216
    217	name = ti_dt_clk_name(node);
    218	clk = _register_mux(NULL, name, parent_names, num_parents,
    219			    flags, &reg, shift, mask, latch, clk_mux_flags,
    220			    NULL);
    221
    222	if (!IS_ERR(clk))
    223		of_clk_add_provider(node, of_clk_src_simple_get, clk);
    224
    225cleanup:
    226	kfree(parent_names);
    227}
    228CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
    229
    230struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup)
    231{
    232	struct clk_omap_mux *mux;
    233	int num_parents;
    234
    235	if (!setup)
    236		return NULL;
    237
    238	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
    239	if (!mux)
    240		return ERR_PTR(-ENOMEM);
    241
    242	mux->shift = setup->bit_shift;
    243	mux->latch = -EINVAL;
    244
    245	mux->reg.index = setup->module;
    246	mux->reg.offset = setup->reg;
    247
    248	if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
    249		mux->flags |= CLK_MUX_INDEX_ONE;
    250
    251	num_parents = setup->num_parents;
    252
    253	mux->mask = num_parents - 1;
    254	mux->mask = (1 << fls(mux->mask)) - 1;
    255
    256	return &mux->hw;
    257}
    258
    259static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
    260{
    261	struct clk_omap_mux *mux;
    262	unsigned int num_parents;
    263	u32 val;
    264
    265	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
    266	if (!mux)
    267		return;
    268
    269	if (ti_clk_get_reg_addr(node, 0, &mux->reg))
    270		goto cleanup;
    271
    272	if (!of_property_read_u32(node, "ti,bit-shift", &val))
    273		mux->shift = val;
    274
    275	if (of_property_read_bool(node, "ti,index-starts-at-one"))
    276		mux->flags |= CLK_MUX_INDEX_ONE;
    277
    278	num_parents = of_clk_get_parent_count(node);
    279
    280	if (num_parents < 2) {
    281		pr_err("%pOFn must have parents\n", node);
    282		goto cleanup;
    283	}
    284
    285	mux->mask = num_parents - 1;
    286	mux->mask = (1 << fls(mux->mask)) - 1;
    287
    288	if (!ti_clk_add_component(node, &mux->hw, CLK_COMPONENT_TYPE_MUX))
    289		return;
    290
    291cleanup:
    292	kfree(mux);
    293}
    294CLK_OF_DECLARE(ti_composite_mux_clk_setup, "ti,composite-mux-clock",
    295	       of_ti_composite_mux_clk_setup);