Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.19-rc5 271 lines 6.3 kB view raw
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 35static 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 73static 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 82static 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 88static DEFINE_SPINLOCK(sun9i_a80_pll4_lock); 89 90static 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} 94CLK_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 103static 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 126static struct clk_factors_config sun9i_a80_gt_config = { 127 .mshift = 0, 128 .mwidth = 2, 129}; 130 131static 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 138static DEFINE_SPINLOCK(sun9i_a80_gt_lock); 139 140static 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} 149CLK_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 158static 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 181static struct clk_factors_config sun9i_a80_ahb_config = { 182 .pshift = 0, 183 .pwidth = 2, 184}; 185 186static 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 193static DEFINE_SPINLOCK(sun9i_a80_ahb_lock); 194 195static 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} 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 sunxi_factors_register(node, &sun9i_a80_apb0_data, &sun9i_a80_apb0_lock); 214} 215CLK_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 224static 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 251static struct clk_factors_config sun9i_a80_apb1_config = { 252 .mshift = 0, 253 .mwidth = 5, 254 .pshift = 16, 255 .pwidth = 2, 256}; 257 258static 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 265static DEFINE_SPINLOCK(sun9i_a80_apb1_lock); 266 267static 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} 271CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);