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-corediv.c (9298B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * MVEBU Core divider clock
      4 *
      5 * Copyright (C) 2013 Marvell
      6 *
      7 * Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
      8 *
      9 */
     10
     11#include <linux/kernel.h>
     12#include <linux/clk-provider.h>
     13#include <linux/io.h>
     14#include <linux/of_address.h>
     15#include <linux/slab.h>
     16#include <linux/delay.h>
     17#include "common.h"
     18
     19#define CORE_CLK_DIV_RATIO_MASK		0xff
     20
     21/*
     22 * This structure describes the hardware details (bit offset and mask)
     23 * to configure one particular core divider clock. Those hardware
     24 * details may differ from one SoC to another. This structure is
     25 * therefore typically instantiated statically to describe the
     26 * hardware details.
     27 */
     28struct clk_corediv_desc {
     29	unsigned int mask;
     30	unsigned int offset;
     31	unsigned int fieldbit;
     32};
     33
     34/*
     35 * This structure describes the hardware details to configure the core
     36 * divider clocks on a given SoC. Amongst others, it points to the
     37 * array of core divider clock descriptors for this SoC, as well as
     38 * the corresponding operations to manipulate them.
     39 */
     40struct clk_corediv_soc_desc {
     41	const struct clk_corediv_desc *descs;
     42	unsigned int ndescs;
     43	const struct clk_ops ops;
     44	u32 ratio_reload;
     45	u32 enable_bit_offset;
     46	u32 ratio_offset;
     47};
     48
     49/*
     50 * This structure represents one core divider clock for the clock
     51 * framework, and is dynamically allocated for each core divider clock
     52 * existing in the current SoC.
     53 */
     54struct clk_corediv {
     55	struct clk_hw hw;
     56	void __iomem *reg;
     57	const struct clk_corediv_desc *desc;
     58	const struct clk_corediv_soc_desc *soc_desc;
     59	spinlock_t lock;
     60};
     61
     62static struct clk_onecell_data clk_data;
     63
     64/*
     65 * Description of the core divider clocks available. For now, we
     66 * support only NAND, and it is available at the same register
     67 * locations regardless of the SoC.
     68 */
     69static const struct clk_corediv_desc mvebu_corediv_desc[] = {
     70	{ .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */
     71};
     72
     73static const struct clk_corediv_desc mv98dx3236_corediv_desc[] = {
     74	{ .mask = 0x0f, .offset = 6, .fieldbit = 27 }, /* NAND clock */
     75};
     76
     77#define to_corediv_clk(p) container_of(p, struct clk_corediv, hw)
     78
     79static int clk_corediv_is_enabled(struct clk_hw *hwclk)
     80{
     81	struct clk_corediv *corediv = to_corediv_clk(hwclk);
     82	const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
     83	const struct clk_corediv_desc *desc = corediv->desc;
     84	u32 enable_mask = BIT(desc->fieldbit) << soc_desc->enable_bit_offset;
     85
     86	return !!(readl(corediv->reg) & enable_mask);
     87}
     88
     89static int clk_corediv_enable(struct clk_hw *hwclk)
     90{
     91	struct clk_corediv *corediv = to_corediv_clk(hwclk);
     92	const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
     93	const struct clk_corediv_desc *desc = corediv->desc;
     94	unsigned long flags = 0;
     95	u32 reg;
     96
     97	spin_lock_irqsave(&corediv->lock, flags);
     98
     99	reg = readl(corediv->reg);
    100	reg |= (BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
    101	writel(reg, corediv->reg);
    102
    103	spin_unlock_irqrestore(&corediv->lock, flags);
    104
    105	return 0;
    106}
    107
    108static void clk_corediv_disable(struct clk_hw *hwclk)
    109{
    110	struct clk_corediv *corediv = to_corediv_clk(hwclk);
    111	const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
    112	const struct clk_corediv_desc *desc = corediv->desc;
    113	unsigned long flags = 0;
    114	u32 reg;
    115
    116	spin_lock_irqsave(&corediv->lock, flags);
    117
    118	reg = readl(corediv->reg);
    119	reg &= ~(BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
    120	writel(reg, corediv->reg);
    121
    122	spin_unlock_irqrestore(&corediv->lock, flags);
    123}
    124
    125static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk,
    126					 unsigned long parent_rate)
    127{
    128	struct clk_corediv *corediv = to_corediv_clk(hwclk);
    129	const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
    130	const struct clk_corediv_desc *desc = corediv->desc;
    131	u32 reg, div;
    132
    133	reg = readl(corediv->reg + soc_desc->ratio_offset);
    134	div = (reg >> desc->offset) & desc->mask;
    135	return parent_rate / div;
    136}
    137
    138static long clk_corediv_round_rate(struct clk_hw *hwclk, unsigned long rate,
    139			       unsigned long *parent_rate)
    140{
    141	/* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */
    142	u32 div;
    143
    144	div = *parent_rate / rate;
    145	if (div < 4)
    146		div = 4;
    147	else if (div > 6)
    148		div = 8;
    149
    150	return *parent_rate / div;
    151}
    152
    153static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
    154			    unsigned long parent_rate)
    155{
    156	struct clk_corediv *corediv = to_corediv_clk(hwclk);
    157	const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
    158	const struct clk_corediv_desc *desc = corediv->desc;
    159	unsigned long flags = 0;
    160	u32 reg, div;
    161
    162	div = parent_rate / rate;
    163
    164	spin_lock_irqsave(&corediv->lock, flags);
    165
    166	/* Write new divider to the divider ratio register */
    167	reg = readl(corediv->reg + soc_desc->ratio_offset);
    168	reg &= ~(desc->mask << desc->offset);
    169	reg |= (div & desc->mask) << desc->offset;
    170	writel(reg, corediv->reg + soc_desc->ratio_offset);
    171
    172	/* Set reload-force for this clock */
    173	reg = readl(corediv->reg) | BIT(desc->fieldbit);
    174	writel(reg, corediv->reg);
    175
    176	/* Now trigger the clock update */
    177	reg = readl(corediv->reg) | soc_desc->ratio_reload;
    178	writel(reg, corediv->reg);
    179
    180	/*
    181	 * Wait for clocks to settle down, and then clear all the
    182	 * ratios request and the reload request.
    183	 */
    184	udelay(1000);
    185	reg &= ~(CORE_CLK_DIV_RATIO_MASK | soc_desc->ratio_reload);
    186	writel(reg, corediv->reg);
    187	udelay(1000);
    188
    189	spin_unlock_irqrestore(&corediv->lock, flags);
    190
    191	return 0;
    192}
    193
    194static const struct clk_corediv_soc_desc armada370_corediv_soc = {
    195	.descs = mvebu_corediv_desc,
    196	.ndescs = ARRAY_SIZE(mvebu_corediv_desc),
    197	.ops = {
    198		.enable = clk_corediv_enable,
    199		.disable = clk_corediv_disable,
    200		.is_enabled = clk_corediv_is_enabled,
    201		.recalc_rate = clk_corediv_recalc_rate,
    202		.round_rate = clk_corediv_round_rate,
    203		.set_rate = clk_corediv_set_rate,
    204	},
    205	.ratio_reload = BIT(8),
    206	.enable_bit_offset = 24,
    207	.ratio_offset = 0x8,
    208};
    209
    210static const struct clk_corediv_soc_desc armada380_corediv_soc = {
    211	.descs = mvebu_corediv_desc,
    212	.ndescs = ARRAY_SIZE(mvebu_corediv_desc),
    213	.ops = {
    214		.enable = clk_corediv_enable,
    215		.disable = clk_corediv_disable,
    216		.is_enabled = clk_corediv_is_enabled,
    217		.recalc_rate = clk_corediv_recalc_rate,
    218		.round_rate = clk_corediv_round_rate,
    219		.set_rate = clk_corediv_set_rate,
    220	},
    221	.ratio_reload = BIT(8),
    222	.enable_bit_offset = 16,
    223	.ratio_offset = 0x4,
    224};
    225
    226static const struct clk_corediv_soc_desc armada375_corediv_soc = {
    227	.descs = mvebu_corediv_desc,
    228	.ndescs = ARRAY_SIZE(mvebu_corediv_desc),
    229	.ops = {
    230		.recalc_rate = clk_corediv_recalc_rate,
    231		.round_rate = clk_corediv_round_rate,
    232		.set_rate = clk_corediv_set_rate,
    233	},
    234	.ratio_reload = BIT(8),
    235	.ratio_offset = 0x4,
    236};
    237
    238static const struct clk_corediv_soc_desc mv98dx3236_corediv_soc = {
    239	.descs = mv98dx3236_corediv_desc,
    240	.ndescs = ARRAY_SIZE(mv98dx3236_corediv_desc),
    241	.ops = {
    242		.recalc_rate = clk_corediv_recalc_rate,
    243		.round_rate = clk_corediv_round_rate,
    244		.set_rate = clk_corediv_set_rate,
    245	},
    246	.ratio_reload = BIT(10),
    247	.ratio_offset = 0x8,
    248};
    249
    250static void __init
    251mvebu_corediv_clk_init(struct device_node *node,
    252		       const struct clk_corediv_soc_desc *soc_desc)
    253{
    254	struct clk_init_data init;
    255	struct clk_corediv *corediv;
    256	struct clk **clks;
    257	void __iomem *base;
    258	const char *parent_name;
    259	const char *clk_name;
    260	int i;
    261
    262	base = of_iomap(node, 0);
    263	if (WARN_ON(!base))
    264		return;
    265
    266	parent_name = of_clk_get_parent_name(node, 0);
    267
    268	clk_data.clk_num = soc_desc->ndescs;
    269
    270	/* clks holds the clock array */
    271	clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
    272				GFP_KERNEL);
    273	if (WARN_ON(!clks))
    274		goto err_unmap;
    275	/* corediv holds the clock specific array */
    276	corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv),
    277				GFP_KERNEL);
    278	if (WARN_ON(!corediv))
    279		goto err_free_clks;
    280
    281	spin_lock_init(&corediv->lock);
    282
    283	for (i = 0; i < clk_data.clk_num; i++) {
    284		of_property_read_string_index(node, "clock-output-names",
    285					      i, &clk_name);
    286		init.num_parents = 1;
    287		init.parent_names = &parent_name;
    288		init.name = clk_name;
    289		init.ops = &soc_desc->ops;
    290		init.flags = 0;
    291
    292		corediv[i].soc_desc = soc_desc;
    293		corediv[i].desc = soc_desc->descs + i;
    294		corediv[i].reg = base;
    295		corediv[i].hw.init = &init;
    296
    297		clks[i] = clk_register(NULL, &corediv[i].hw);
    298		WARN_ON(IS_ERR(clks[i]));
    299	}
    300
    301	clk_data.clks = clks;
    302	of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data);
    303	return;
    304
    305err_free_clks:
    306	kfree(clks);
    307err_unmap:
    308	iounmap(base);
    309}
    310
    311static void __init armada370_corediv_clk_init(struct device_node *node)
    312{
    313	return mvebu_corediv_clk_init(node, &armada370_corediv_soc);
    314}
    315CLK_OF_DECLARE(armada370_corediv_clk, "marvell,armada-370-corediv-clock",
    316	       armada370_corediv_clk_init);
    317
    318static void __init armada375_corediv_clk_init(struct device_node *node)
    319{
    320	return mvebu_corediv_clk_init(node, &armada375_corediv_soc);
    321}
    322CLK_OF_DECLARE(armada375_corediv_clk, "marvell,armada-375-corediv-clock",
    323	       armada375_corediv_clk_init);
    324
    325static void __init armada380_corediv_clk_init(struct device_node *node)
    326{
    327	return mvebu_corediv_clk_init(node, &armada380_corediv_soc);
    328}
    329CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock",
    330	       armada380_corediv_clk_init);
    331
    332static void __init mv98dx3236_corediv_clk_init(struct device_node *node)
    333{
    334	return mvebu_corediv_clk_init(node, &mv98dx3236_corediv_soc);
    335}
    336CLK_OF_DECLARE(mv98dx3236_corediv_clk, "marvell,mv98dx3236-corediv-clock",
    337	       mv98dx3236_corediv_clk_init);