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

divider.c (12985B)


      1/*
      2 * TI Divider 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 unsigned int _get_table_div(const struct clk_div_table *table,
     30				   unsigned int val)
     31{
     32	const struct clk_div_table *clkt;
     33
     34	for (clkt = table; clkt->div; clkt++)
     35		if (clkt->val == val)
     36			return clkt->div;
     37	return 0;
     38}
     39
     40static void _setup_mask(struct clk_omap_divider *divider)
     41{
     42	u16 mask;
     43	u32 max_val;
     44	const struct clk_div_table *clkt;
     45
     46	if (divider->table) {
     47		max_val = 0;
     48
     49		for (clkt = divider->table; clkt->div; clkt++)
     50			if (clkt->val > max_val)
     51				max_val = clkt->val;
     52	} else {
     53		max_val = divider->max;
     54
     55		if (!(divider->flags & CLK_DIVIDER_ONE_BASED) &&
     56		    !(divider->flags & CLK_DIVIDER_POWER_OF_TWO))
     57			max_val--;
     58	}
     59
     60	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
     61		mask = fls(max_val) - 1;
     62	else
     63		mask = max_val;
     64
     65	divider->mask = (1 << fls(mask)) - 1;
     66}
     67
     68static unsigned int _get_div(struct clk_omap_divider *divider, unsigned int val)
     69{
     70	if (divider->flags & CLK_DIVIDER_ONE_BASED)
     71		return val;
     72	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
     73		return 1 << val;
     74	if (divider->table)
     75		return _get_table_div(divider->table, val);
     76	return val + 1;
     77}
     78
     79static unsigned int _get_table_val(const struct clk_div_table *table,
     80				   unsigned int div)
     81{
     82	const struct clk_div_table *clkt;
     83
     84	for (clkt = table; clkt->div; clkt++)
     85		if (clkt->div == div)
     86			return clkt->val;
     87	return 0;
     88}
     89
     90static unsigned int _get_val(struct clk_omap_divider *divider, u8 div)
     91{
     92	if (divider->flags & CLK_DIVIDER_ONE_BASED)
     93		return div;
     94	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
     95		return __ffs(div);
     96	if (divider->table)
     97		return  _get_table_val(divider->table, div);
     98	return div - 1;
     99}
    100
    101static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw,
    102						unsigned long parent_rate)
    103{
    104	struct clk_omap_divider *divider = to_clk_omap_divider(hw);
    105	unsigned int div, val;
    106
    107	val = ti_clk_ll_ops->clk_readl(&divider->reg) >> divider->shift;
    108	val &= divider->mask;
    109
    110	div = _get_div(divider, val);
    111	if (!div) {
    112		WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
    113		     "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
    114		     clk_hw_get_name(hw));
    115		return parent_rate;
    116	}
    117
    118	return DIV_ROUND_UP(parent_rate, div);
    119}
    120
    121/*
    122 * The reverse of DIV_ROUND_UP: The maximum number which
    123 * divided by m is r
    124 */
    125#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
    126
    127static bool _is_valid_table_div(const struct clk_div_table *table,
    128				unsigned int div)
    129{
    130	const struct clk_div_table *clkt;
    131
    132	for (clkt = table; clkt->div; clkt++)
    133		if (clkt->div == div)
    134			return true;
    135	return false;
    136}
    137
    138static bool _is_valid_div(struct clk_omap_divider *divider, unsigned int div)
    139{
    140	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
    141		return is_power_of_2(div);
    142	if (divider->table)
    143		return _is_valid_table_div(divider->table, div);
    144	return true;
    145}
    146
    147static int _div_round_up(const struct clk_div_table *table,
    148			 unsigned long parent_rate, unsigned long rate)
    149{
    150	const struct clk_div_table *clkt;
    151	int up = INT_MAX;
    152	int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
    153
    154	for (clkt = table; clkt->div; clkt++) {
    155		if (clkt->div == div)
    156			return clkt->div;
    157		else if (clkt->div < div)
    158			continue;
    159
    160		if ((clkt->div - div) < (up - div))
    161			up = clkt->div;
    162	}
    163
    164	return up;
    165}
    166
    167static int _div_round(const struct clk_div_table *table,
    168		      unsigned long parent_rate, unsigned long rate)
    169{
    170	if (!table)
    171		return DIV_ROUND_UP(parent_rate, rate);
    172
    173	return _div_round_up(table, parent_rate, rate);
    174}
    175
    176static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
    177				  unsigned long *best_parent_rate)
    178{
    179	struct clk_omap_divider *divider = to_clk_omap_divider(hw);
    180	int i, bestdiv = 0;
    181	unsigned long parent_rate, best = 0, now, maxdiv;
    182	unsigned long parent_rate_saved = *best_parent_rate;
    183
    184	if (!rate)
    185		rate = 1;
    186
    187	maxdiv = divider->max;
    188
    189	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
    190		parent_rate = *best_parent_rate;
    191		bestdiv = _div_round(divider->table, parent_rate, rate);
    192		bestdiv = bestdiv == 0 ? 1 : bestdiv;
    193		bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
    194		return bestdiv;
    195	}
    196
    197	/*
    198	 * The maximum divider we can use without overflowing
    199	 * unsigned long in rate * i below
    200	 */
    201	maxdiv = min(ULONG_MAX / rate, maxdiv);
    202
    203	for (i = 1; i <= maxdiv; i++) {
    204		if (!_is_valid_div(divider, i))
    205			continue;
    206		if (rate * i == parent_rate_saved) {
    207			/*
    208			 * It's the most ideal case if the requested rate can be
    209			 * divided from parent clock without needing to change
    210			 * parent rate, so return the divider immediately.
    211			 */
    212			*best_parent_rate = parent_rate_saved;
    213			return i;
    214		}
    215		parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
    216				MULT_ROUND_UP(rate, i));
    217		now = DIV_ROUND_UP(parent_rate, i);
    218		if (now <= rate && now > best) {
    219			bestdiv = i;
    220			best = now;
    221			*best_parent_rate = parent_rate;
    222		}
    223	}
    224
    225	if (!bestdiv) {
    226		bestdiv = divider->max;
    227		*best_parent_rate =
    228			clk_hw_round_rate(clk_hw_get_parent(hw), 1);
    229	}
    230
    231	return bestdiv;
    232}
    233
    234static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
    235				      unsigned long *prate)
    236{
    237	int div;
    238	div = ti_clk_divider_bestdiv(hw, rate, prate);
    239
    240	return DIV_ROUND_UP(*prate, div);
    241}
    242
    243static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
    244				   unsigned long parent_rate)
    245{
    246	struct clk_omap_divider *divider;
    247	unsigned int div, value;
    248	u32 val;
    249
    250	if (!hw || !rate)
    251		return -EINVAL;
    252
    253	divider = to_clk_omap_divider(hw);
    254
    255	div = DIV_ROUND_UP(parent_rate, rate);
    256
    257	if (div > divider->max)
    258		div = divider->max;
    259	if (div < divider->min)
    260		div = divider->min;
    261
    262	value = _get_val(divider, div);
    263
    264	val = ti_clk_ll_ops->clk_readl(&divider->reg);
    265	val &= ~(divider->mask << divider->shift);
    266	val |= value << divider->shift;
    267	ti_clk_ll_ops->clk_writel(val, &divider->reg);
    268
    269	ti_clk_latch(&divider->reg, divider->latch);
    270
    271	return 0;
    272}
    273
    274/**
    275 * clk_divider_save_context - Save the divider value
    276 * @hw: pointer  struct clk_hw
    277 *
    278 * Save the divider value
    279 */
    280static int clk_divider_save_context(struct clk_hw *hw)
    281{
    282	struct clk_omap_divider *divider = to_clk_omap_divider(hw);
    283	u32 val;
    284
    285	val = ti_clk_ll_ops->clk_readl(&divider->reg) >> divider->shift;
    286	divider->context = val & divider->mask;
    287
    288	return 0;
    289}
    290
    291/**
    292 * clk_divider_restore_context - restore the saved the divider value
    293 * @hw: pointer  struct clk_hw
    294 *
    295 * Restore the saved the divider value
    296 */
    297static void clk_divider_restore_context(struct clk_hw *hw)
    298{
    299	struct clk_omap_divider *divider = to_clk_omap_divider(hw);
    300	u32 val;
    301
    302	val = ti_clk_ll_ops->clk_readl(&divider->reg);
    303	val &= ~(divider->mask << divider->shift);
    304	val |= divider->context << divider->shift;
    305	ti_clk_ll_ops->clk_writel(val, &divider->reg);
    306}
    307
    308const struct clk_ops ti_clk_divider_ops = {
    309	.recalc_rate = ti_clk_divider_recalc_rate,
    310	.round_rate = ti_clk_divider_round_rate,
    311	.set_rate = ti_clk_divider_set_rate,
    312	.save_context = clk_divider_save_context,
    313	.restore_context = clk_divider_restore_context,
    314};
    315
    316static struct clk *_register_divider(struct device_node *node,
    317				     u32 flags,
    318				     struct clk_omap_divider *div)
    319{
    320	struct clk *clk;
    321	struct clk_init_data init;
    322	const char *parent_name;
    323	const char *name;
    324
    325	parent_name = of_clk_get_parent_name(node, 0);
    326
    327	name = ti_dt_clk_name(node);
    328	init.name = name;
    329	init.ops = &ti_clk_divider_ops;
    330	init.flags = flags;
    331	init.parent_names = (parent_name ? &parent_name : NULL);
    332	init.num_parents = (parent_name ? 1 : 0);
    333
    334	div->hw.init = &init;
    335
    336	/* register the clock */
    337	clk = ti_clk_register(NULL, &div->hw, name);
    338
    339	if (IS_ERR(clk))
    340		kfree(div);
    341
    342	return clk;
    343}
    344
    345int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div,
    346			      u8 flags, struct clk_omap_divider *divider)
    347{
    348	int valid_div = 0;
    349	int i;
    350	struct clk_div_table *tmp;
    351	u16 min_div = 0;
    352
    353	if (!div_table) {
    354		divider->min = 1;
    355		divider->max = max_div;
    356		_setup_mask(divider);
    357		return 0;
    358	}
    359
    360	i = 0;
    361
    362	while (!num_dividers || i < num_dividers) {
    363		if (div_table[i] == -1)
    364			break;
    365		if (div_table[i])
    366			valid_div++;
    367		i++;
    368	}
    369
    370	num_dividers = i;
    371
    372	tmp = kcalloc(valid_div + 1, sizeof(*tmp), GFP_KERNEL);
    373	if (!tmp)
    374		return -ENOMEM;
    375
    376	valid_div = 0;
    377
    378	for (i = 0; i < num_dividers; i++)
    379		if (div_table[i] > 0) {
    380			tmp[valid_div].div = div_table[i];
    381			tmp[valid_div].val = i;
    382			valid_div++;
    383			if (div_table[i] > max_div)
    384				max_div = div_table[i];
    385			if (!min_div || div_table[i] < min_div)
    386				min_div = div_table[i];
    387		}
    388
    389	divider->min = min_div;
    390	divider->max = max_div;
    391	divider->table = tmp;
    392	_setup_mask(divider);
    393
    394	return 0;
    395}
    396
    397static int __init ti_clk_get_div_table(struct device_node *node,
    398				       struct clk_omap_divider *div)
    399{
    400	struct clk_div_table *table;
    401	const __be32 *divspec;
    402	u32 val;
    403	u32 num_div;
    404	u32 valid_div;
    405	int i;
    406
    407	divspec = of_get_property(node, "ti,dividers", &num_div);
    408
    409	if (!divspec)
    410		return 0;
    411
    412	num_div /= 4;
    413
    414	valid_div = 0;
    415
    416	/* Determine required size for divider table */
    417	for (i = 0; i < num_div; i++) {
    418		of_property_read_u32_index(node, "ti,dividers", i, &val);
    419		if (val)
    420			valid_div++;
    421	}
    422
    423	if (!valid_div) {
    424		pr_err("no valid dividers for %pOFn table\n", node);
    425		return -EINVAL;
    426	}
    427
    428	table = kcalloc(valid_div + 1, sizeof(*table), GFP_KERNEL);
    429	if (!table)
    430		return -ENOMEM;
    431
    432	valid_div = 0;
    433
    434	for (i = 0; i < num_div; i++) {
    435		of_property_read_u32_index(node, "ti,dividers", i, &val);
    436		if (val) {
    437			table[valid_div].div = val;
    438			table[valid_div].val = i;
    439			valid_div++;
    440		}
    441	}
    442
    443	div->table = table;
    444
    445	return 0;
    446}
    447
    448static int _populate_divider_min_max(struct device_node *node,
    449				     struct clk_omap_divider *divider)
    450{
    451	u32 min_div = 0;
    452	u32 max_div = 0;
    453	u32 val;
    454	const struct clk_div_table *clkt;
    455
    456	if (!divider->table) {
    457		/* Clk divider table not provided, determine min/max divs */
    458		if (of_property_read_u32(node, "ti,min-div", &min_div))
    459			min_div = 1;
    460
    461		if (of_property_read_u32(node, "ti,max-div", &max_div)) {
    462			pr_err("no max-div for %pOFn!\n", node);
    463			return -EINVAL;
    464		}
    465	} else {
    466
    467		for (clkt = divider->table; clkt->div; clkt++) {
    468			val = clkt->div;
    469			if (val > max_div)
    470				max_div = val;
    471			if (!min_div || val < min_div)
    472				min_div = val;
    473		}
    474	}
    475
    476	divider->min = min_div;
    477	divider->max = max_div;
    478	_setup_mask(divider);
    479
    480	return 0;
    481}
    482
    483static int __init ti_clk_divider_populate(struct device_node *node,
    484					  struct clk_omap_divider *div,
    485					  u32 *flags)
    486{
    487	u32 val;
    488	int ret;
    489
    490	ret = ti_clk_get_reg_addr(node, 0, &div->reg);
    491	if (ret)
    492		return ret;
    493
    494	if (!of_property_read_u32(node, "ti,bit-shift", &val))
    495		div->shift = val;
    496	else
    497		div->shift = 0;
    498
    499	if (!of_property_read_u32(node, "ti,latch-bit", &val))
    500		div->latch = val;
    501	else
    502		div->latch = -EINVAL;
    503
    504	*flags = 0;
    505	div->flags = 0;
    506
    507	if (of_property_read_bool(node, "ti,index-starts-at-one"))
    508		div->flags |= CLK_DIVIDER_ONE_BASED;
    509
    510	if (of_property_read_bool(node, "ti,index-power-of-two"))
    511		div->flags |= CLK_DIVIDER_POWER_OF_TWO;
    512
    513	if (of_property_read_bool(node, "ti,set-rate-parent"))
    514		*flags |= CLK_SET_RATE_PARENT;
    515
    516	ret = ti_clk_get_div_table(node, div);
    517	if (ret)
    518		return ret;
    519
    520	return _populate_divider_min_max(node, div);
    521}
    522
    523/**
    524 * of_ti_divider_clk_setup - Setup function for simple div rate clock
    525 * @node: device node for this clock
    526 *
    527 * Sets up a basic divider clock.
    528 */
    529static void __init of_ti_divider_clk_setup(struct device_node *node)
    530{
    531	struct clk *clk;
    532	u32 flags = 0;
    533	struct clk_omap_divider *div;
    534
    535	div = kzalloc(sizeof(*div), GFP_KERNEL);
    536	if (!div)
    537		return;
    538
    539	if (ti_clk_divider_populate(node, div, &flags))
    540		goto cleanup;
    541
    542	clk = _register_divider(node, flags, div);
    543	if (!IS_ERR(clk)) {
    544		of_clk_add_provider(node, of_clk_src_simple_get, clk);
    545		of_ti_clk_autoidle_setup(node);
    546		return;
    547	}
    548
    549cleanup:
    550	kfree(div->table);
    551	kfree(div);
    552}
    553CLK_OF_DECLARE(divider_clk, "ti,divider-clock", of_ti_divider_clk_setup);
    554
    555static void __init of_ti_composite_divider_clk_setup(struct device_node *node)
    556{
    557	struct clk_omap_divider *div;
    558	u32 tmp;
    559
    560	div = kzalloc(sizeof(*div), GFP_KERNEL);
    561	if (!div)
    562		return;
    563
    564	if (ti_clk_divider_populate(node, div, &tmp))
    565		goto cleanup;
    566
    567	if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER))
    568		return;
    569
    570cleanup:
    571	kfree(div->table);
    572	kfree(div);
    573}
    574CLK_OF_DECLARE(ti_composite_divider_clk, "ti,composite-divider-clock",
    575	       of_ti_composite_divider_clk_setup);