root/drivers/clk/sunxi/clk-sun9i-core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun9i_a80_get_pll4_factors
  2. sun9i_a80_pll4_setup
  3. sun9i_a80_get_gt_factors
  4. sun9i_a80_gt_setup
  5. sun9i_a80_get_ahb_factors
  6. sun9i_a80_ahb_setup
  7. sun9i_a80_apb0_setup
  8. sun9i_a80_get_apb1_factors
  9. sun9i_a80_apb1_setup

   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 
  26 static 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 
  59 static 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 
  68 static 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 
  74 static DEFINE_SPINLOCK(sun9i_a80_pll4_lock);
  75 
  76 static 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 }
  90 CLK_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 
  99 static 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 
 116 static const struct clk_factors_config sun9i_a80_gt_config = {
 117         .mshift = 0,
 118         .mwidth = 2,
 119 };
 120 
 121 static 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 
 128 static DEFINE_SPINLOCK(sun9i_a80_gt_lock);
 129 
 130 static 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 }
 145 CLK_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 
 154 static 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 
 171 static const struct clk_factors_config sun9i_a80_ahb_config = {
 172         .pshift = 0,
 173         .pwidth = 2,
 174 };
 175 
 176 static 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 
 183 static DEFINE_SPINLOCK(sun9i_a80_ahb_lock);
 184 
 185 static 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 }
 199 CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup);
 200 
 201 
 202 static 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 
 209 static DEFINE_SPINLOCK(sun9i_a80_apb0_lock);
 210 
 211 static 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 }
 225 CLK_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 
 234 static 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 
 252 static const struct clk_factors_config sun9i_a80_apb1_config = {
 253         .mshift = 0,
 254         .mwidth = 5,
 255         .pshift = 16,
 256         .pwidth = 2,
 257 };
 258 
 259 static 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 
 266 static DEFINE_SPINLOCK(sun9i_a80_apb1_lock);
 267 
 268 static 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 }
 282 CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);

/* [<][>][^][v][top][bottom][index][help] */