1/* 2 * Copyright 2014 Chen-Yu Tsai 3 * 4 * Chen-Yu Tsai <wens@csie.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17#include <linux/clk-provider.h> 18#include <linux/clkdev.h> 19#include <linux/of.h> 20#include <linux/of_address.h> 21#include <linux/log2.h> 22 23#include "clk-factors.h" 24 25 26/** 27 * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL4 28 * PLL4 rate is calculated as follows 29 * rate = (parent_rate * n >> p) / (m + 1); 30 * parent_rate is always 24MHz 31 * 32 * p and m are named div1 and div2 in Allwinner's SDK 33 */ 34 35static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate, 36 u8 *n_ret, u8 *k, u8 *m_ret, u8 *p_ret) 37{ 38 int n; 39 int m = 1; 40 int p = 1; 41 42 /* Normalize value to a 6 MHz multiple (24 MHz / 4) */ 43 n = DIV_ROUND_UP(*freq, 6000000); 44 45 /* If n is too large switch to steps of 12 MHz */ 46 if (n > 255) { 47 m = 0; 48 n = (n + 1) / 2; 49 } 50 51 /* If n is still too large switch to steps of 24 MHz */ 52 if (n > 255) { 53 p = 0; 54 n = (n + 1) / 2; 55 } 56 57 /* n must be between 12 and 255 */ 58 if (n > 255) 59 n = 255; 60 else if (n < 12) 61 n = 12; 62 63 *freq = ((24000000 * n) >> p) / (m + 1); 64 65 /* we were called to round the frequency, we can now return */ 66 if (n_ret == NULL) 67 return; 68 69 *n_ret = n; 70 *m_ret = m; 71 *p_ret = p; 72} 73 74static struct clk_factors_config sun9i_a80_pll4_config = { 75 .mshift = 18, 76 .mwidth = 1, 77 .nshift = 8, 78 .nwidth = 8, 79 .pshift = 16, 80 .pwidth = 1, 81}; 82 83static const struct factors_data sun9i_a80_pll4_data __initconst = { 84 .enable = 31, 85 .table = &sun9i_a80_pll4_config, 86 .getter = sun9i_a80_get_pll4_factors, 87}; 88 89static DEFINE_SPINLOCK(sun9i_a80_pll4_lock); 90 91static void __init sun9i_a80_pll4_setup(struct device_node *node) 92{ 93 void __iomem *reg; 94 95 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 96 if (!reg) { 97 pr_err("Could not get registers for a80-pll4-clk: %s\n", 98 node->name); 99 return; 100 } 101 102 sunxi_factors_register(node, &sun9i_a80_pll4_data, 103 &sun9i_a80_pll4_lock, reg); 104} 105CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup); 106 107 108/** 109 * sun9i_a80_get_gt_factors() - calculates m factor for GT 110 * GT rate is calculated as follows 111 * rate = parent_rate / (m + 1); 112 */ 113 114static void sun9i_a80_get_gt_factors(u32 *freq, u32 parent_rate, 115 u8 *n, u8 *k, u8 *m, u8 *p) 116{ 117 u32 div; 118 119 if (parent_rate < *freq) 120 *freq = parent_rate; 121 122 div = DIV_ROUND_UP(parent_rate, *freq); 123 124 /* maximum divider is 4 */ 125 if (div > 4) 126 div = 4; 127 128 *freq = parent_rate / div; 129 130 /* we were called to round the frequency, we can now return */ 131 if (!m) 132 return; 133 134 *m = div; 135} 136 137static struct clk_factors_config sun9i_a80_gt_config = { 138 .mshift = 0, 139 .mwidth = 2, 140}; 141 142static const struct factors_data sun9i_a80_gt_data __initconst = { 143 .mux = 24, 144 .muxmask = BIT(1) | BIT(0), 145 .table = &sun9i_a80_gt_config, 146 .getter = sun9i_a80_get_gt_factors, 147}; 148 149static DEFINE_SPINLOCK(sun9i_a80_gt_lock); 150 151static void __init sun9i_a80_gt_setup(struct device_node *node) 152{ 153 void __iomem *reg; 154 struct clk *gt; 155 156 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 157 if (!reg) { 158 pr_err("Could not get registers for a80-gt-clk: %s\n", 159 node->name); 160 return; 161 } 162 163 gt = sunxi_factors_register(node, &sun9i_a80_gt_data, 164 &sun9i_a80_gt_lock, reg); 165 166 /* The GT bus clock needs to be always enabled */ 167 __clk_get(gt); 168 clk_prepare_enable(gt); 169} 170CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup); 171 172 173/** 174 * sun9i_a80_get_ahb_factors() - calculates p factor for AHB0/1/2 175 * AHB rate is calculated as follows 176 * rate = parent_rate >> p; 177 */ 178 179static void sun9i_a80_get_ahb_factors(u32 *freq, u32 parent_rate, 180 u8 *n, u8 *k, u8 *m, u8 *p) 181{ 182 u32 _p; 183 184 if (parent_rate < *freq) 185 *freq = parent_rate; 186 187 _p = order_base_2(DIV_ROUND_UP(parent_rate, *freq)); 188 189 /* maximum p is 3 */ 190 if (_p > 3) 191 _p = 3; 192 193 *freq = parent_rate >> _p; 194 195 /* we were called to round the frequency, we can now return */ 196 if (!p) 197 return; 198 199 *p = _p; 200} 201 202static struct clk_factors_config sun9i_a80_ahb_config = { 203 .pshift = 0, 204 .pwidth = 2, 205}; 206 207static const struct factors_data sun9i_a80_ahb_data __initconst = { 208 .mux = 24, 209 .muxmask = BIT(1) | BIT(0), 210 .table = &sun9i_a80_ahb_config, 211 .getter = sun9i_a80_get_ahb_factors, 212}; 213 214static DEFINE_SPINLOCK(sun9i_a80_ahb_lock); 215 216static void __init sun9i_a80_ahb_setup(struct device_node *node) 217{ 218 void __iomem *reg; 219 220 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 221 if (!reg) { 222 pr_err("Could not get registers for a80-ahb-clk: %s\n", 223 node->name); 224 return; 225 } 226 227 sunxi_factors_register(node, &sun9i_a80_ahb_data, 228 &sun9i_a80_ahb_lock, reg); 229} 230CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup); 231 232 233static const struct factors_data sun9i_a80_apb0_data __initconst = { 234 .mux = 24, 235 .muxmask = BIT(0), 236 .table = &sun9i_a80_ahb_config, 237 .getter = sun9i_a80_get_ahb_factors, 238}; 239 240static DEFINE_SPINLOCK(sun9i_a80_apb0_lock); 241 242static void __init sun9i_a80_apb0_setup(struct device_node *node) 243{ 244 void __iomem *reg; 245 246 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 247 if (!reg) { 248 pr_err("Could not get registers for a80-apb0-clk: %s\n", 249 node->name); 250 return; 251 } 252 253 sunxi_factors_register(node, &sun9i_a80_apb0_data, 254 &sun9i_a80_apb0_lock, reg); 255} 256CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup); 257 258 259/** 260 * sun9i_a80_get_apb1_factors() - calculates m, p factors for APB1 261 * APB1 rate is calculated as follows 262 * rate = (parent_rate >> p) / (m + 1); 263 */ 264 265static void sun9i_a80_get_apb1_factors(u32 *freq, u32 parent_rate, 266 u8 *n, u8 *k, u8 *m, u8 *p) 267{ 268 u32 div; 269 u8 calcm, calcp; 270 271 if (parent_rate < *freq) 272 *freq = parent_rate; 273 274 div = DIV_ROUND_UP(parent_rate, *freq); 275 276 /* Highest possible divider is 256 (p = 3, m = 31) */ 277 if (div > 256) 278 div = 256; 279 280 calcp = order_base_2(div); 281 calcm = (parent_rate >> calcp) - 1; 282 *freq = (parent_rate >> calcp) / (calcm + 1); 283 284 /* we were called to round the frequency, we can now return */ 285 if (n == NULL) 286 return; 287 288 *m = calcm; 289 *p = calcp; 290} 291 292static struct clk_factors_config sun9i_a80_apb1_config = { 293 .mshift = 0, 294 .mwidth = 5, 295 .pshift = 16, 296 .pwidth = 2, 297}; 298 299static const struct factors_data sun9i_a80_apb1_data __initconst = { 300 .mux = 24, 301 .muxmask = BIT(0), 302 .table = &sun9i_a80_apb1_config, 303 .getter = sun9i_a80_get_apb1_factors, 304}; 305 306static DEFINE_SPINLOCK(sun9i_a80_apb1_lock); 307 308static void __init sun9i_a80_apb1_setup(struct device_node *node) 309{ 310 void __iomem *reg; 311 312 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 313 if (!reg) { 314 pr_err("Could not get registers for a80-apb1-clk: %s\n", 315 node->name); 316 return; 317 } 318 319 sunxi_factors_register(node, &sun9i_a80_apb1_data, 320 &sun9i_a80_apb1_lock, reg); 321} 322CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup); 323