brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · d93c7a5 Raw
283 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright 2014 Chen-Yu Tsai4 *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 PLL419 * PLL4 rate is calculated as follows20 * rate = (parent_rate * n >> p) / (m + 1);21 * parent_rate is always 24MHz22 *23 * p and m are named div1 and div2 in Allwinner's SDK24 */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 GT95 * GT rate is calculated as follows96 * 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/2150 * AHB rate is calculated as follows151 * 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 APB1230 * APB1 rate is calculated as follows231 * 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);283