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 PLL1 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 35 static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate, 36 u8 *n, u8 *k, u8 *m, u8 *p) 37 { 38 int div; 39 40 /* Normalize value to a 6M multiple */ 41 div = DIV_ROUND_UP(*freq, 6000000); 42 43 /* divs above 256 cannot be odd */ 44 if (div > 256) 45 div = round_up(div, 2); 46 47 /* divs above 512 must be a multiple of 4 */ 48 if (div > 512) 49 div = round_up(div, 4); 50 51 *freq = 6000000 * div; 52 53 /* we were called to round the frequency, we can now return */ 54 if (n == NULL) 55 return; 56 57 /* p will be 1 for divs under 512 */ 58 if (div < 512) 59 *p = 1; 60 else 61 *p = 0; 62 63 /* m will be 1 if div is odd */ 64 if (div & 1) 65 *m = 1; 66 else 67 *m = 0; 68 69 /* calculate a suitable n based on m and p */ 70 *n = div / (*p + 1) / (*m + 1); 71 } 72 73 static struct clk_factors_config sun9i_a80_pll4_config = { 74 .mshift = 18, 75 .mwidth = 1, 76 .nshift = 8, 77 .nwidth = 8, 78 .pshift = 16, 79 .pwidth = 1, 80 }; 81 82 static const struct factors_data sun9i_a80_pll4_data __initconst = { 83 .enable = 31, 84 .table = &sun9i_a80_pll4_config, 85 .getter = sun9i_a80_get_pll4_factors, 86 }; 87 88 static DEFINE_SPINLOCK(sun9i_a80_pll4_lock); 89 90 static void __init sun9i_a80_pll4_setup(struct device_node *node) 91 { 92 sunxi_factors_register(node, &sun9i_a80_pll4_data, &sun9i_a80_pll4_lock); 93 } 94 CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup); 95 96 97 /** 98 * sun9i_a80_get_gt_factors() - calculates m factor for GT 99 * GT rate is calculated as follows 100 * rate = parent_rate / (m + 1); 101 */ 102 103 static void sun9i_a80_get_gt_factors(u32 *freq, u32 parent_rate, 104 u8 *n, u8 *k, u8 *m, u8 *p) 105 { 106 u32 div; 107 108 if (parent_rate < *freq) 109 *freq = parent_rate; 110 111 div = DIV_ROUND_UP(parent_rate, *freq); 112 113 /* maximum divider is 4 */ 114 if (div > 4) 115 div = 4; 116 117 *freq = parent_rate / div; 118 119 /* we were called to round the frequency, we can now return */ 120 if (!m) 121 return; 122 123 *m = div; 124 } 125 126 static struct clk_factors_config sun9i_a80_gt_config = { 127 .mshift = 0, 128 .mwidth = 2, 129 }; 130 131 static const struct factors_data sun9i_a80_gt_data __initconst = { 132 .mux = 24, 133 .muxmask = BIT(1) | BIT(0), 134 .table = &sun9i_a80_gt_config, 135 .getter = sun9i_a80_get_gt_factors, 136 }; 137 138 static DEFINE_SPINLOCK(sun9i_a80_gt_lock); 139 140 static void __init sun9i_a80_gt_setup(struct device_node *node) 141 { 142 struct clk *gt = sunxi_factors_register(node, &sun9i_a80_gt_data, 143 &sun9i_a80_gt_lock); 144 145 /* The GT bus clock needs to be always enabled */ 146 __clk_get(gt); 147 clk_prepare_enable(gt); 148 } 149 CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup); 150 151 152 /** 153 * sun9i_a80_get_ahb_factors() - calculates p factor for AHB0/1/2 154 * AHB rate is calculated as follows 155 * rate = parent_rate >> p; 156 */ 157 158 static void sun9i_a80_get_ahb_factors(u32 *freq, u32 parent_rate, 159 u8 *n, u8 *k, u8 *m, u8 *p) 160 { 161 u32 _p; 162 163 if (parent_rate < *freq) 164 *freq = parent_rate; 165 166 _p = order_base_2(DIV_ROUND_UP(parent_rate, *freq)); 167 168 /* maximum p is 3 */ 169 if (_p > 3) 170 _p = 3; 171 172 *freq = parent_rate >> _p; 173 174 /* we were called to round the frequency, we can now return */ 175 if (!p) 176 return; 177 178 *p = _p; 179 } 180 181 static struct clk_factors_config sun9i_a80_ahb_config = { 182 .pshift = 0, 183 .pwidth = 2, 184 }; 185 186 static const struct factors_data sun9i_a80_ahb_data __initconst = { 187 .mux = 24, 188 .muxmask = BIT(1) | BIT(0), 189 .table = &sun9i_a80_ahb_config, 190 .getter = sun9i_a80_get_ahb_factors, 191 }; 192 193 static DEFINE_SPINLOCK(sun9i_a80_ahb_lock); 194 195 static void __init sun9i_a80_ahb_setup(struct device_node *node) 196 { 197 sunxi_factors_register(node, &sun9i_a80_ahb_data, &sun9i_a80_ahb_lock); 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 sunxi_factors_register(node, &sun9i_a80_apb0_data, &sun9i_a80_apb0_lock); 214 } 215 CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup); 216 217 218 /** 219 * sun9i_a80_get_apb1_factors() - calculates m, p factors for APB1 220 * APB1 rate is calculated as follows 221 * rate = (parent_rate >> p) / (m + 1); 222 */ 223 224 static void sun9i_a80_get_apb1_factors(u32 *freq, u32 parent_rate, 225 u8 *n, u8 *k, u8 *m, u8 *p) 226 { 227 u32 div; 228 u8 calcm, calcp; 229 230 if (parent_rate < *freq) 231 *freq = parent_rate; 232 233 div = DIV_ROUND_UP(parent_rate, *freq); 234 235 /* Highest possible divider is 256 (p = 3, m = 31) */ 236 if (div > 256) 237 div = 256; 238 239 calcp = order_base_2(div); 240 calcm = (parent_rate >> calcp) - 1; 241 *freq = (parent_rate >> calcp) / (calcm + 1); 242 243 /* we were called to round the frequency, we can now return */ 244 if (n == NULL) 245 return; 246 247 *m = calcm; 248 *p = calcp; 249 } 250 251 static struct clk_factors_config sun9i_a80_apb1_config = { 252 .mshift = 0, 253 .mwidth = 5, 254 .pshift = 16, 255 .pwidth = 2, 256 }; 257 258 static const struct factors_data sun9i_a80_apb1_data __initconst = { 259 .mux = 24, 260 .muxmask = BIT(0), 261 .table = &sun9i_a80_apb1_config, 262 .getter = sun9i_a80_get_apb1_factors, 263 }; 264 265 static DEFINE_SPINLOCK(sun9i_a80_apb1_lock); 266 267 static void __init sun9i_a80_apb1_setup(struct device_node *node) 268 { 269 sunxi_factors_register(node, &sun9i_a80_apb1_data, &sun9i_a80_apb1_lock); 270 } 271 CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup); 272