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-mod0.c (8914B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2013 Emilio López
      4 *
      5 * Emilio López <emilio@elopez.com.ar>
      6 */
      7
      8#include <linux/clk.h>
      9#include <linux/clk-provider.h>
     10#include <linux/io.h>
     11#include <linux/of_address.h>
     12#include <linux/platform_device.h>
     13#include <linux/slab.h>
     14
     15#include "clk-factors.h"
     16
     17/*
     18 * sun4i_a10_get_mod0_factors() - calculates m, n factors for MOD0-style clocks
     19 * MOD0 rate is calculated as follows
     20 * rate = (parent_rate >> p) / (m + 1);
     21 */
     22
     23static void sun4i_a10_get_mod0_factors(struct factors_request *req)
     24{
     25	u8 div, calcm, calcp;
     26
     27	/* These clocks can only divide, so we will never be able to achieve
     28	 * frequencies higher than the parent frequency */
     29	if (req->rate > req->parent_rate)
     30		req->rate = req->parent_rate;
     31
     32	div = DIV_ROUND_UP(req->parent_rate, req->rate);
     33
     34	if (div < 16)
     35		calcp = 0;
     36	else if (div / 2 < 16)
     37		calcp = 1;
     38	else if (div / 4 < 16)
     39		calcp = 2;
     40	else
     41		calcp = 3;
     42
     43	calcm = DIV_ROUND_UP(div, 1 << calcp);
     44
     45	req->rate = (req->parent_rate >> calcp) / calcm;
     46	req->m = calcm - 1;
     47	req->p = calcp;
     48}
     49
     50/* user manual says "n" but it's really "p" */
     51static const struct clk_factors_config sun4i_a10_mod0_config = {
     52	.mshift = 0,
     53	.mwidth = 4,
     54	.pshift = 16,
     55	.pwidth = 2,
     56};
     57
     58static const struct factors_data sun4i_a10_mod0_data = {
     59	.enable = 31,
     60	.mux = 24,
     61	.muxmask = BIT(1) | BIT(0),
     62	.table = &sun4i_a10_mod0_config,
     63	.getter = sun4i_a10_get_mod0_factors,
     64};
     65
     66static DEFINE_SPINLOCK(sun4i_a10_mod0_lock);
     67
     68static void __init sun4i_a10_mod0_setup(struct device_node *node)
     69{
     70	void __iomem *reg;
     71
     72	reg = of_iomap(node, 0);
     73	if (!reg) {
     74		/*
     75		 * This happens with mod0 clk nodes instantiated through
     76		 * mfd, as those do not have their resources assigned at
     77		 * CLK_OF_DECLARE time yet, so do not print an error.
     78		 */
     79		return;
     80	}
     81
     82	sunxi_factors_register(node, &sun4i_a10_mod0_data,
     83			       &sun4i_a10_mod0_lock, reg);
     84}
     85CLK_OF_DECLARE_DRIVER(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk",
     86		      sun4i_a10_mod0_setup);
     87
     88static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev)
     89{
     90	struct device_node *np = pdev->dev.of_node;
     91	void __iomem *reg;
     92
     93	if (!np)
     94		return -ENODEV;
     95
     96	reg = devm_platform_ioremap_resource(pdev, 0);
     97	if (IS_ERR(reg))
     98		return PTR_ERR(reg);
     99
    100	sunxi_factors_register(np, &sun4i_a10_mod0_data,
    101			       &sun4i_a10_mod0_lock, reg);
    102	return 0;
    103}
    104
    105static const struct of_device_id sun4i_a10_mod0_clk_dt_ids[] = {
    106	{ .compatible = "allwinner,sun4i-a10-mod0-clk" },
    107	{ /* sentinel */ }
    108};
    109
    110static struct platform_driver sun4i_a10_mod0_clk_driver = {
    111	.driver = {
    112		.name = "sun4i-a10-mod0-clk",
    113		.of_match_table = sun4i_a10_mod0_clk_dt_ids,
    114	},
    115	.probe = sun4i_a10_mod0_clk_probe,
    116};
    117builtin_platform_driver(sun4i_a10_mod0_clk_driver);
    118
    119static const struct factors_data sun9i_a80_mod0_data __initconst = {
    120	.enable = 31,
    121	.mux = 24,
    122	.muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
    123	.table = &sun4i_a10_mod0_config,
    124	.getter = sun4i_a10_get_mod0_factors,
    125};
    126
    127static void __init sun9i_a80_mod0_setup(struct device_node *node)
    128{
    129	void __iomem *reg;
    130
    131	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
    132	if (IS_ERR(reg)) {
    133		pr_err("Could not get registers for mod0-clk: %pOFn\n",
    134		       node);
    135		return;
    136	}
    137
    138	sunxi_factors_register(node, &sun9i_a80_mod0_data,
    139			       &sun4i_a10_mod0_lock, reg);
    140}
    141CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk", sun9i_a80_mod0_setup);
    142
    143static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
    144
    145static void __init sun5i_a13_mbus_setup(struct device_node *node)
    146{
    147	void __iomem *reg;
    148
    149	reg = of_iomap(node, 0);
    150	if (!reg) {
    151		pr_err("Could not get registers for a13-mbus-clk\n");
    152		return;
    153	}
    154
    155	/* The MBUS clocks needs to be always enabled */
    156	sunxi_factors_register_critical(node, &sun4i_a10_mod0_data,
    157					&sun5i_a13_mbus_lock, reg);
    158}
    159CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
    160
    161struct mmc_phase {
    162	struct clk_hw		hw;
    163	u8			offset;
    164	void __iomem		*reg;
    165	spinlock_t		*lock;
    166};
    167
    168#define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw)
    169
    170static int mmc_get_phase(struct clk_hw *hw)
    171{
    172	struct clk *mmc, *mmc_parent, *clk = hw->clk;
    173	struct mmc_phase *phase = to_mmc_phase(hw);
    174	unsigned int mmc_rate, mmc_parent_rate;
    175	u16 step, mmc_div;
    176	u32 value;
    177	u8 delay;
    178
    179	value = readl(phase->reg);
    180	delay = (value >> phase->offset) & 0x3;
    181
    182	if (!delay)
    183		return 180;
    184
    185	/* Get the main MMC clock */
    186	mmc = clk_get_parent(clk);
    187	if (!mmc)
    188		return -EINVAL;
    189
    190	/* And its rate */
    191	mmc_rate = clk_get_rate(mmc);
    192	if (!mmc_rate)
    193		return -EINVAL;
    194
    195	/* Now, get the MMC parent (most likely some PLL) */
    196	mmc_parent = clk_get_parent(mmc);
    197	if (!mmc_parent)
    198		return -EINVAL;
    199
    200	/* And its rate */
    201	mmc_parent_rate = clk_get_rate(mmc_parent);
    202	if (!mmc_parent_rate)
    203		return -EINVAL;
    204
    205	/* Get MMC clock divider */
    206	mmc_div = mmc_parent_rate / mmc_rate;
    207
    208	step = DIV_ROUND_CLOSEST(360, mmc_div);
    209	return delay * step;
    210}
    211
    212static int mmc_set_phase(struct clk_hw *hw, int degrees)
    213{
    214	struct clk *mmc, *mmc_parent, *clk = hw->clk;
    215	struct mmc_phase *phase = to_mmc_phase(hw);
    216	unsigned int mmc_rate, mmc_parent_rate;
    217	unsigned long flags;
    218	u32 value;
    219	u8 delay;
    220
    221	/* Get the main MMC clock */
    222	mmc = clk_get_parent(clk);
    223	if (!mmc)
    224		return -EINVAL;
    225
    226	/* And its rate */
    227	mmc_rate = clk_get_rate(mmc);
    228	if (!mmc_rate)
    229		return -EINVAL;
    230
    231	/* Now, get the MMC parent (most likely some PLL) */
    232	mmc_parent = clk_get_parent(mmc);
    233	if (!mmc_parent)
    234		return -EINVAL;
    235
    236	/* And its rate */
    237	mmc_parent_rate = clk_get_rate(mmc_parent);
    238	if (!mmc_parent_rate)
    239		return -EINVAL;
    240
    241	if (degrees != 180) {
    242		u16 step, mmc_div;
    243
    244		/* Get MMC clock divider */
    245		mmc_div = mmc_parent_rate / mmc_rate;
    246
    247		/*
    248		 * We can only outphase the clocks by multiple of the
    249		 * PLL's period.
    250		 *
    251		 * Since the MMC clock in only a divider, and the
    252		 * formula to get the outphasing in degrees is deg =
    253		 * 360 * delta / period
    254		 *
    255		 * If we simplify this formula, we can see that the
    256		 * only thing that we're concerned about is the number
    257		 * of period we want to outphase our clock from, and
    258		 * the divider set by the MMC clock.
    259		 */
    260		step = DIV_ROUND_CLOSEST(360, mmc_div);
    261		delay = DIV_ROUND_CLOSEST(degrees, step);
    262	} else {
    263		delay = 0;
    264	}
    265
    266	spin_lock_irqsave(phase->lock, flags);
    267	value = readl(phase->reg);
    268	value &= ~GENMASK(phase->offset + 3, phase->offset);
    269	value |= delay << phase->offset;
    270	writel(value, phase->reg);
    271	spin_unlock_irqrestore(phase->lock, flags);
    272
    273	return 0;
    274}
    275
    276static const struct clk_ops mmc_clk_ops = {
    277	.get_phase	= mmc_get_phase,
    278	.set_phase	= mmc_set_phase,
    279};
    280
    281/*
    282 * sunxi_mmc_setup - Common setup function for mmc module clocks
    283 *
    284 * The only difference between module clocks on different platforms is the
    285 * width of the mux register bits and the valid values, which are passed in
    286 * through struct factors_data. The phase clocks parts are identical.
    287 */
    288static void __init sunxi_mmc_setup(struct device_node *node,
    289				   const struct factors_data *data,
    290				   spinlock_t *lock)
    291{
    292	struct clk_onecell_data *clk_data;
    293	const char *parent;
    294	void __iomem *reg;
    295	int i;
    296
    297	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
    298	if (IS_ERR(reg)) {
    299		pr_err("Couldn't map the %pOFn clock registers\n", node);
    300		return;
    301	}
    302
    303	clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
    304	if (!clk_data)
    305		return;
    306
    307	clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
    308	if (!clk_data->clks)
    309		goto err_free_data;
    310
    311	clk_data->clk_num = 3;
    312	clk_data->clks[0] = sunxi_factors_register(node, data, lock, reg);
    313	if (!clk_data->clks[0])
    314		goto err_free_clks;
    315
    316	parent = __clk_get_name(clk_data->clks[0]);
    317
    318	for (i = 1; i < 3; i++) {
    319		struct clk_init_data init = {
    320			.num_parents	= 1,
    321			.parent_names	= &parent,
    322			.ops		= &mmc_clk_ops,
    323		};
    324		struct mmc_phase *phase;
    325
    326		phase = kmalloc(sizeof(*phase), GFP_KERNEL);
    327		if (!phase)
    328			continue;
    329
    330		phase->hw.init = &init;
    331		phase->reg = reg;
    332		phase->lock = lock;
    333
    334		if (i == 1)
    335			phase->offset = 8;
    336		else
    337			phase->offset = 20;
    338
    339		if (of_property_read_string_index(node, "clock-output-names",
    340						  i, &init.name))
    341			init.name = node->name;
    342
    343		clk_data->clks[i] = clk_register(NULL, &phase->hw);
    344		if (IS_ERR(clk_data->clks[i])) {
    345			kfree(phase);
    346			continue;
    347		}
    348	}
    349
    350	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
    351
    352	return;
    353
    354err_free_clks:
    355	kfree(clk_data->clks);
    356err_free_data:
    357	kfree(clk_data);
    358}
    359
    360static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
    361
    362static void __init sun4i_a10_mmc_setup(struct device_node *node)
    363{
    364	sunxi_mmc_setup(node, &sun4i_a10_mod0_data, &sun4i_a10_mmc_lock);
    365}
    366CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
    367
    368static DEFINE_SPINLOCK(sun9i_a80_mmc_lock);
    369
    370static void __init sun9i_a80_mmc_setup(struct device_node *node)
    371{
    372	sunxi_mmc_setup(node, &sun9i_a80_mod0_data, &sun9i_a80_mmc_lock);
    373}
    374CLK_OF_DECLARE(sun9i_a80_mmc, "allwinner,sun9i-a80-mmc-clk", sun9i_a80_mmc_setup);