Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2014 Chen-Yu Tsai
0004  *
0005  * Chen-Yu Tsai <wens@csie.org>
0006  */
0007 
0008 #include <linux/clk.h>
0009 #include <linux/clk-provider.h>
0010 #include <linux/of.h>
0011 #include <linux/of_address.h>
0012 #include <linux/log2.h>
0013 
0014 #include "clk-factors.h"
0015 
0016 
0017 /*
0018  * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL4
0019  * PLL4 rate is calculated as follows
0020  * rate = (parent_rate * n >> p) / (m + 1);
0021  * parent_rate is always 24MHz
0022  *
0023  * p and m are named div1 and div2 in Allwinner's SDK
0024  */
0025 
0026 static void sun9i_a80_get_pll4_factors(struct factors_request *req)
0027 {
0028     int n;
0029     int m = 1;
0030     int p = 1;
0031 
0032     /* Normalize value to a 6 MHz multiple (24 MHz / 4) */
0033     n = DIV_ROUND_UP(req->rate, 6000000);
0034 
0035     /* If n is too large switch to steps of 12 MHz */
0036     if (n > 255) {
0037         m = 0;
0038         n = (n + 1) / 2;
0039     }
0040 
0041     /* If n is still too large switch to steps of 24 MHz */
0042     if (n > 255) {
0043         p = 0;
0044         n = (n + 1) / 2;
0045     }
0046 
0047     /* n must be between 12 and 255 */
0048     if (n > 255)
0049         n = 255;
0050     else if (n < 12)
0051         n = 12;
0052 
0053     req->rate = ((24000000 * n) >> p) / (m + 1);
0054     req->n = n;
0055     req->m = m;
0056     req->p = p;
0057 }
0058 
0059 static const struct clk_factors_config sun9i_a80_pll4_config = {
0060     .mshift = 18,
0061     .mwidth = 1,
0062     .nshift = 8,
0063     .nwidth = 8,
0064     .pshift = 16,
0065     .pwidth = 1,
0066 };
0067 
0068 static const struct factors_data sun9i_a80_pll4_data __initconst = {
0069     .enable = 31,
0070     .table = &sun9i_a80_pll4_config,
0071     .getter = sun9i_a80_get_pll4_factors,
0072 };
0073 
0074 static DEFINE_SPINLOCK(sun9i_a80_pll4_lock);
0075 
0076 static void __init sun9i_a80_pll4_setup(struct device_node *node)
0077 {
0078     void __iomem *reg;
0079 
0080     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0081     if (IS_ERR(reg)) {
0082         pr_err("Could not get registers for a80-pll4-clk: %pOFn\n",
0083                node);
0084         return;
0085     }
0086 
0087     sunxi_factors_register(node, &sun9i_a80_pll4_data,
0088                    &sun9i_a80_pll4_lock, reg);
0089 }
0090 CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup);
0091 
0092 
0093 /*
0094  * sun9i_a80_get_gt_factors() - calculates m factor for GT
0095  * GT rate is calculated as follows
0096  * rate = parent_rate / (m + 1);
0097  */
0098 
0099 static void sun9i_a80_get_gt_factors(struct factors_request *req)
0100 {
0101     u32 div;
0102 
0103     if (req->parent_rate < req->rate)
0104         req->rate = req->parent_rate;
0105 
0106     div = DIV_ROUND_UP(req->parent_rate, req->rate);
0107 
0108     /* maximum divider is 4 */
0109     if (div > 4)
0110         div = 4;
0111 
0112     req->rate = req->parent_rate / div;
0113     req->m = div;
0114 }
0115 
0116 static const struct clk_factors_config sun9i_a80_gt_config = {
0117     .mshift = 0,
0118     .mwidth = 2,
0119 };
0120 
0121 static const struct factors_data sun9i_a80_gt_data __initconst = {
0122     .mux = 24,
0123     .muxmask = BIT(1) | BIT(0),
0124     .table = &sun9i_a80_gt_config,
0125     .getter = sun9i_a80_get_gt_factors,
0126 };
0127 
0128 static DEFINE_SPINLOCK(sun9i_a80_gt_lock);
0129 
0130 static void __init sun9i_a80_gt_setup(struct device_node *node)
0131 {
0132     void __iomem *reg;
0133 
0134     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0135     if (IS_ERR(reg)) {
0136         pr_err("Could not get registers for a80-gt-clk: %pOFn\n",
0137                node);
0138         return;
0139     }
0140 
0141     /* The GT bus clock needs to be always enabled */
0142     sunxi_factors_register_critical(node, &sun9i_a80_gt_data,
0143                     &sun9i_a80_gt_lock, reg);
0144 }
0145 CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup);
0146 
0147 
0148 /*
0149  * sun9i_a80_get_ahb_factors() - calculates p factor for AHB0/1/2
0150  * AHB rate is calculated as follows
0151  * rate = parent_rate >> p;
0152  */
0153 
0154 static void sun9i_a80_get_ahb_factors(struct factors_request *req)
0155 {
0156     u32 _p;
0157 
0158     if (req->parent_rate < req->rate)
0159         req->rate = req->parent_rate;
0160 
0161     _p = order_base_2(DIV_ROUND_UP(req->parent_rate, req->rate));
0162 
0163     /* maximum p is 3 */
0164     if (_p > 3)
0165         _p = 3;
0166 
0167     req->rate = req->parent_rate >> _p;
0168     req->p = _p;
0169 }
0170 
0171 static const struct clk_factors_config sun9i_a80_ahb_config = {
0172     .pshift = 0,
0173     .pwidth = 2,
0174 };
0175 
0176 static const struct factors_data sun9i_a80_ahb_data __initconst = {
0177     .mux = 24,
0178     .muxmask = BIT(1) | BIT(0),
0179     .table = &sun9i_a80_ahb_config,
0180     .getter = sun9i_a80_get_ahb_factors,
0181 };
0182 
0183 static DEFINE_SPINLOCK(sun9i_a80_ahb_lock);
0184 
0185 static void __init sun9i_a80_ahb_setup(struct device_node *node)
0186 {
0187     void __iomem *reg;
0188 
0189     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0190     if (IS_ERR(reg)) {
0191         pr_err("Could not get registers for a80-ahb-clk: %pOFn\n",
0192                node);
0193         return;
0194     }
0195 
0196     sunxi_factors_register(node, &sun9i_a80_ahb_data,
0197                    &sun9i_a80_ahb_lock, reg);
0198 }
0199 CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup);
0200 
0201 
0202 static const struct factors_data sun9i_a80_apb0_data __initconst = {
0203     .mux = 24,
0204     .muxmask = BIT(0),
0205     .table = &sun9i_a80_ahb_config,
0206     .getter = sun9i_a80_get_ahb_factors,
0207 };
0208 
0209 static DEFINE_SPINLOCK(sun9i_a80_apb0_lock);
0210 
0211 static void __init sun9i_a80_apb0_setup(struct device_node *node)
0212 {
0213     void __iomem *reg;
0214 
0215     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0216     if (IS_ERR(reg)) {
0217         pr_err("Could not get registers for a80-apb0-clk: %pOFn\n",
0218                node);
0219         return;
0220     }
0221 
0222     sunxi_factors_register(node, &sun9i_a80_apb0_data,
0223                    &sun9i_a80_apb0_lock, reg);
0224 }
0225 CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup);
0226 
0227 
0228 /*
0229  * sun9i_a80_get_apb1_factors() - calculates m, p factors for APB1
0230  * APB1 rate is calculated as follows
0231  * rate = (parent_rate >> p) / (m + 1);
0232  */
0233 
0234 static void sun9i_a80_get_apb1_factors(struct factors_request *req)
0235 {
0236     u32 div;
0237 
0238     if (req->parent_rate < req->rate)
0239         req->rate = req->parent_rate;
0240 
0241     div = DIV_ROUND_UP(req->parent_rate, req->rate);
0242 
0243     /* Highest possible divider is 256 (p = 3, m = 31) */
0244     if (div > 256)
0245         div = 256;
0246 
0247     req->p = order_base_2(div);
0248     req->m = (req->parent_rate >> req->p) - 1;
0249     req->rate = (req->parent_rate >> req->p) / (req->m + 1);
0250 }
0251 
0252 static const struct clk_factors_config sun9i_a80_apb1_config = {
0253     .mshift = 0,
0254     .mwidth = 5,
0255     .pshift = 16,
0256     .pwidth = 2,
0257 };
0258 
0259 static const struct factors_data sun9i_a80_apb1_data __initconst = {
0260     .mux = 24,
0261     .muxmask = BIT(0),
0262     .table = &sun9i_a80_apb1_config,
0263     .getter = sun9i_a80_get_apb1_factors,
0264 };
0265 
0266 static DEFINE_SPINLOCK(sun9i_a80_apb1_lock);
0267 
0268 static void __init sun9i_a80_apb1_setup(struct device_node *node)
0269 {
0270     void __iomem *reg;
0271 
0272     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0273     if (IS_ERR(reg)) {
0274         pr_err("Could not get registers for a80-apb1-clk: %pOFn\n",
0275                node);
0276         return;
0277     }
0278 
0279     sunxi_factors_register(node, &sun9i_a80_apb1_data,
0280                    &sun9i_a80_apb1_lock, reg);
0281 }
0282 CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);