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.h> 18 #include <linux/clk-provider.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 35 static void sun9i_a80_get_pll4_factors(struct factors_request *req) 36 { 37 int n; 38 int m = 1; 39 int p = 1; 40 41 /* Normalize value to a 6 MHz multiple (24 MHz / 4) */ 42 n = DIV_ROUND_UP(req->rate, 6000000); 43 44 /* If n is too large switch to steps of 12 MHz */ 45 if (n > 255) { 46 m = 0; 47 n = (n + 1) / 2; 48 } 49 50 /* If n is still too large switch to steps of 24 MHz */ 51 if (n > 255) { 52 p = 0; 53 n = (n + 1) / 2; 54 } 55 56 /* n must be between 12 and 255 */ 57 if (n > 255) 58 n = 255; 59 else if (n < 12) 60 n = 12; 61 62 req->rate = ((24000000 * n) >> p) / (m + 1); 63 req->n = n; 64 req->m = m; 65 req->p = p; 66 } 67 68 static const struct clk_factors_config sun9i_a80_pll4_config = { 69 .mshift = 18, 70 .mwidth = 1, 71 .nshift = 8, 72 .nwidth = 8, 73 .pshift = 16, 74 .pwidth = 1, 75 }; 76 77 static const struct factors_data sun9i_a80_pll4_data __initconst = { 78 .enable = 31, 79 .table = &sun9i_a80_pll4_config, 80 .getter = sun9i_a80_get_pll4_factors, 81 }; 82 83 static DEFINE_SPINLOCK(sun9i_a80_pll4_lock); 84 85 static void __init sun9i_a80_pll4_setup(struct device_node *node) 86 { 87 void __iomem *reg; 88 89 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 90 if (IS_ERR(reg)) { 91 pr_err("Could not get registers for a80-pll4-clk: %pOFn\n", 92 node); 93 return; 94 } 95 96 sunxi_factors_register(node, &sun9i_a80_pll4_data, 97 &sun9i_a80_pll4_lock, reg); 98 } 99 CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup); 100 101 102 /** 103 * sun9i_a80_get_gt_factors() - calculates m factor for GT 104 * GT rate is calculated as follows 105 * rate = parent_rate / (m + 1); 106 */ 107 108 static void sun9i_a80_get_gt_factors(struct factors_request *req) 109 { 110 u32 div; 111 112 if (req->parent_rate < req->rate) 113 req->rate = req->parent_rate; 114 115 div = DIV_ROUND_UP(req->parent_rate, req->rate); 116 117 /* maximum divider is 4 */ 118 if (div > 4) 119 div = 4; 120 121 req->rate = req->parent_rate / div; 122 req->m = div; 123 } 124 125 static const struct clk_factors_config sun9i_a80_gt_config = { 126 .mshift = 0, 127 .mwidth = 2, 128 }; 129 130 static const struct factors_data sun9i_a80_gt_data __initconst = { 131 .mux = 24, 132 .muxmask = BIT(1) | BIT(0), 133 .table = &sun9i_a80_gt_config, 134 .getter = sun9i_a80_get_gt_factors, 135 }; 136 137 static DEFINE_SPINLOCK(sun9i_a80_gt_lock); 138 139 static void __init sun9i_a80_gt_setup(struct device_node *node) 140 { 141 void __iomem *reg; 142 143 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 144 if (IS_ERR(reg)) { 145 pr_err("Could not get registers for a80-gt-clk: %pOFn\n", 146 node); 147 return; 148 } 149 150 /* The GT bus clock needs to be always enabled */ 151 sunxi_factors_register_critical(node, &sun9i_a80_gt_data, 152 &sun9i_a80_gt_lock, reg); 153 } 154 CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup); 155 156 157 /** 158 * sun9i_a80_get_ahb_factors() - calculates p factor for AHB0/1/2 159 * AHB rate is calculated as follows 160 * rate = parent_rate >> p; 161 */ 162 163 static void sun9i_a80_get_ahb_factors(struct factors_request *req) 164 { 165 u32 _p; 166 167 if (req->parent_rate < req->rate) 168 req->rate = req->parent_rate; 169 170 _p = order_base_2(DIV_ROUND_UP(req->parent_rate, req->rate)); 171 172 /* maximum p is 3 */ 173 if (_p > 3) 174 _p = 3; 175 176 req->rate = req->parent_rate >> _p; 177 req->p = _p; 178 } 179 180 static const struct clk_factors_config sun9i_a80_ahb_config = { 181 .pshift = 0, 182 .pwidth = 2, 183 }; 184 185 static const struct factors_data sun9i_a80_ahb_data __initconst = { 186 .mux = 24, 187 .muxmask = BIT(1) | BIT(0), 188 .table = &sun9i_a80_ahb_config, 189 .getter = sun9i_a80_get_ahb_factors, 190 }; 191 192 static DEFINE_SPINLOCK(sun9i_a80_ahb_lock); 193 194 static void __init sun9i_a80_ahb_setup(struct device_node *node) 195 { 196 void __iomem *reg; 197 198 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 199 if (IS_ERR(reg)) { 200 pr_err("Could not get registers for a80-ahb-clk: %pOFn\n", 201 node); 202 return; 203 } 204 205 sunxi_factors_register(node, &sun9i_a80_ahb_data, 206 &sun9i_a80_ahb_lock, reg); 207 } 208 CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup); 209 210 211 static const struct factors_data sun9i_a80_apb0_data __initconst = { 212 .mux = 24, 213 .muxmask = BIT(0), 214 .table = &sun9i_a80_ahb_config, 215 .getter = sun9i_a80_get_ahb_factors, 216 }; 217 218 static DEFINE_SPINLOCK(sun9i_a80_apb0_lock); 219 220 static void __init sun9i_a80_apb0_setup(struct device_node *node) 221 { 222 void __iomem *reg; 223 224 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 225 if (IS_ERR(reg)) { 226 pr_err("Could not get registers for a80-apb0-clk: %pOFn\n", 227 node); 228 return; 229 } 230 231 sunxi_factors_register(node, &sun9i_a80_apb0_data, 232 &sun9i_a80_apb0_lock, reg); 233 } 234 CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup); 235 236 237 /** 238 * sun9i_a80_get_apb1_factors() - calculates m, p factors for APB1 239 * APB1 rate is calculated as follows 240 * rate = (parent_rate >> p) / (m + 1); 241 */ 242 243 static void sun9i_a80_get_apb1_factors(struct factors_request *req) 244 { 245 u32 div; 246 247 if (req->parent_rate < req->rate) 248 req->rate = req->parent_rate; 249 250 div = DIV_ROUND_UP(req->parent_rate, req->rate); 251 252 /* Highest possible divider is 256 (p = 3, m = 31) */ 253 if (div > 256) 254 div = 256; 255 256 req->p = order_base_2(div); 257 req->m = (req->parent_rate >> req->p) - 1; 258 req->rate = (req->parent_rate >> req->p) / (req->m + 1); 259 } 260 261 static const struct clk_factors_config sun9i_a80_apb1_config = { 262 .mshift = 0, 263 .mwidth = 5, 264 .pshift = 16, 265 .pwidth = 2, 266 }; 267 268 static const struct factors_data sun9i_a80_apb1_data __initconst = { 269 .mux = 24, 270 .muxmask = BIT(0), 271 .table = &sun9i_a80_apb1_config, 272 .getter = sun9i_a80_get_apb1_factors, 273 }; 274 275 static DEFINE_SPINLOCK(sun9i_a80_apb1_lock); 276 277 static void __init sun9i_a80_apb1_setup(struct device_node *node) 278 { 279 void __iomem *reg; 280 281 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 282 if (IS_ERR(reg)) { 283 pr_err("Could not get registers for a80-apb1-clk: %pOFn\n", 284 node); 285 return; 286 } 287 288 sunxi_factors_register(node, &sun9i_a80_apb1_data, 289 &sun9i_a80_apb1_lock, reg); 290 } 291 CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup); 292