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-sun9i-core.c (6408B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2014 Chen-Yu Tsai
      4 *
      5 * Chen-Yu Tsai <wens@csie.org>
      6 */
      7
      8#include <linux/clk.h>
      9#include <linux/clk-provider.h>
     10#include <linux/of.h>
     11#include <linux/of_address.h>
     12#include <linux/log2.h>
     13
     14#include "clk-factors.h"
     15
     16
     17/*
     18 * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL4
     19 * PLL4 rate is calculated as follows
     20 * rate = (parent_rate * n >> p) / (m + 1);
     21 * parent_rate is always 24MHz
     22 *
     23 * p and m are named div1 and div2 in Allwinner's SDK
     24 */
     25
     26static void sun9i_a80_get_pll4_factors(struct factors_request *req)
     27{
     28	int n;
     29	int m = 1;
     30	int p = 1;
     31
     32	/* Normalize value to a 6 MHz multiple (24 MHz / 4) */
     33	n = DIV_ROUND_UP(req->rate, 6000000);
     34
     35	/* If n is too large switch to steps of 12 MHz */
     36	if (n > 255) {
     37		m = 0;
     38		n = (n + 1) / 2;
     39	}
     40
     41	/* If n is still too large switch to steps of 24 MHz */
     42	if (n > 255) {
     43		p = 0;
     44		n = (n + 1) / 2;
     45	}
     46
     47	/* n must be between 12 and 255 */
     48	if (n > 255)
     49		n = 255;
     50	else if (n < 12)
     51		n = 12;
     52
     53	req->rate = ((24000000 * n) >> p) / (m + 1);
     54	req->n = n;
     55	req->m = m;
     56	req->p = p;
     57}
     58
     59static const struct clk_factors_config sun9i_a80_pll4_config = {
     60	.mshift = 18,
     61	.mwidth = 1,
     62	.nshift = 8,
     63	.nwidth = 8,
     64	.pshift = 16,
     65	.pwidth = 1,
     66};
     67
     68static const struct factors_data sun9i_a80_pll4_data __initconst = {
     69	.enable = 31,
     70	.table = &sun9i_a80_pll4_config,
     71	.getter = sun9i_a80_get_pll4_factors,
     72};
     73
     74static DEFINE_SPINLOCK(sun9i_a80_pll4_lock);
     75
     76static void __init sun9i_a80_pll4_setup(struct device_node *node)
     77{
     78	void __iomem *reg;
     79
     80	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
     81	if (IS_ERR(reg)) {
     82		pr_err("Could not get registers for a80-pll4-clk: %pOFn\n",
     83		       node);
     84		return;
     85	}
     86
     87	sunxi_factors_register(node, &sun9i_a80_pll4_data,
     88			       &sun9i_a80_pll4_lock, reg);
     89}
     90CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup);
     91
     92
     93/*
     94 * sun9i_a80_get_gt_factors() - calculates m factor for GT
     95 * GT rate is calculated as follows
     96 * rate = parent_rate / (m + 1);
     97 */
     98
     99static void sun9i_a80_get_gt_factors(struct factors_request *req)
    100{
    101	u32 div;
    102
    103	if (req->parent_rate < req->rate)
    104		req->rate = req->parent_rate;
    105
    106	div = DIV_ROUND_UP(req->parent_rate, req->rate);
    107
    108	/* maximum divider is 4 */
    109	if (div > 4)
    110		div = 4;
    111
    112	req->rate = req->parent_rate / div;
    113	req->m = div;
    114}
    115
    116static const struct clk_factors_config sun9i_a80_gt_config = {
    117	.mshift = 0,
    118	.mwidth = 2,
    119};
    120
    121static const struct factors_data sun9i_a80_gt_data __initconst = {
    122	.mux = 24,
    123	.muxmask = BIT(1) | BIT(0),
    124	.table = &sun9i_a80_gt_config,
    125	.getter = sun9i_a80_get_gt_factors,
    126};
    127
    128static DEFINE_SPINLOCK(sun9i_a80_gt_lock);
    129
    130static void __init sun9i_a80_gt_setup(struct device_node *node)
    131{
    132	void __iomem *reg;
    133
    134	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
    135	if (IS_ERR(reg)) {
    136		pr_err("Could not get registers for a80-gt-clk: %pOFn\n",
    137		       node);
    138		return;
    139	}
    140
    141	/* The GT bus clock needs to be always enabled */
    142	sunxi_factors_register_critical(node, &sun9i_a80_gt_data,
    143					&sun9i_a80_gt_lock, reg);
    144}
    145CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup);
    146
    147
    148/*
    149 * sun9i_a80_get_ahb_factors() - calculates p factor for AHB0/1/2
    150 * AHB rate is calculated as follows
    151 * rate = parent_rate >> p;
    152 */
    153
    154static void sun9i_a80_get_ahb_factors(struct factors_request *req)
    155{
    156	u32 _p;
    157
    158	if (req->parent_rate < req->rate)
    159		req->rate = req->parent_rate;
    160
    161	_p = order_base_2(DIV_ROUND_UP(req->parent_rate, req->rate));
    162
    163	/* maximum p is 3 */
    164	if (_p > 3)
    165		_p = 3;
    166
    167	req->rate = req->parent_rate >> _p;
    168	req->p = _p;
    169}
    170
    171static const struct clk_factors_config sun9i_a80_ahb_config = {
    172	.pshift = 0,
    173	.pwidth = 2,
    174};
    175
    176static const struct factors_data sun9i_a80_ahb_data __initconst = {
    177	.mux = 24,
    178	.muxmask = BIT(1) | BIT(0),
    179	.table = &sun9i_a80_ahb_config,
    180	.getter = sun9i_a80_get_ahb_factors,
    181};
    182
    183static DEFINE_SPINLOCK(sun9i_a80_ahb_lock);
    184
    185static void __init sun9i_a80_ahb_setup(struct device_node *node)
    186{
    187	void __iomem *reg;
    188
    189	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
    190	if (IS_ERR(reg)) {
    191		pr_err("Could not get registers for a80-ahb-clk: %pOFn\n",
    192		       node);
    193		return;
    194	}
    195
    196	sunxi_factors_register(node, &sun9i_a80_ahb_data,
    197			       &sun9i_a80_ahb_lock, reg);
    198}
    199CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup);
    200
    201
    202static const struct factors_data sun9i_a80_apb0_data __initconst = {
    203	.mux = 24,
    204	.muxmask = BIT(0),
    205	.table = &sun9i_a80_ahb_config,
    206	.getter = sun9i_a80_get_ahb_factors,
    207};
    208
    209static DEFINE_SPINLOCK(sun9i_a80_apb0_lock);
    210
    211static void __init sun9i_a80_apb0_setup(struct device_node *node)
    212{
    213	void __iomem *reg;
    214
    215	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
    216	if (IS_ERR(reg)) {
    217		pr_err("Could not get registers for a80-apb0-clk: %pOFn\n",
    218		       node);
    219		return;
    220	}
    221
    222	sunxi_factors_register(node, &sun9i_a80_apb0_data,
    223			       &sun9i_a80_apb0_lock, reg);
    224}
    225CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup);
    226
    227
    228/*
    229 * sun9i_a80_get_apb1_factors() - calculates m, p factors for APB1
    230 * APB1 rate is calculated as follows
    231 * rate = (parent_rate >> p) / (m + 1);
    232 */
    233
    234static void sun9i_a80_get_apb1_factors(struct factors_request *req)
    235{
    236	u32 div;
    237
    238	if (req->parent_rate < req->rate)
    239		req->rate = req->parent_rate;
    240
    241	div = DIV_ROUND_UP(req->parent_rate, req->rate);
    242
    243	/* Highest possible divider is 256 (p = 3, m = 31) */
    244	if (div > 256)
    245		div = 256;
    246
    247	req->p = order_base_2(div);
    248	req->m = (req->parent_rate >> req->p) - 1;
    249	req->rate = (req->parent_rate >> req->p) / (req->m + 1);
    250}
    251
    252static const struct clk_factors_config sun9i_a80_apb1_config = {
    253	.mshift = 0,
    254	.mwidth = 5,
    255	.pshift = 16,
    256	.pwidth = 2,
    257};
    258
    259static const struct factors_data sun9i_a80_apb1_data __initconst = {
    260	.mux = 24,
    261	.muxmask = BIT(0),
    262	.table = &sun9i_a80_apb1_config,
    263	.getter = sun9i_a80_get_apb1_factors,
    264};
    265
    266static DEFINE_SPINLOCK(sun9i_a80_apb1_lock);
    267
    268static void __init sun9i_a80_apb1_setup(struct device_node *node)
    269{
    270	void __iomem *reg;
    271
    272	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
    273	if (IS_ERR(reg)) {
    274		pr_err("Could not get registers for a80-apb1-clk: %pOFn\n",
    275		       node);
    276		return;
    277	}
    278
    279	sunxi_factors_register(node, &sun9i_a80_apb1_data,
    280			       &sun9i_a80_apb1_lock, reg);
    281}
    282CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);