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