559 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI Divider Clock4 *5 * Copyright (C) 2013 Texas Instruments, Inc.6 *7 * Tero Kristo <t-kristo@ti.com>8 */9 10#include <linux/clk-provider.h>11#include <linux/slab.h>12#include <linux/err.h>13#include <linux/of.h>14#include <linux/of_address.h>15#include <linux/clk/ti.h>16#include "clock.h"17 18#undef pr_fmt19#define pr_fmt(fmt) "%s: " fmt, __func__20 21static unsigned int _get_table_div(const struct clk_div_table *table,22 unsigned int val)23{24 const struct clk_div_table *clkt;25 26 for (clkt = table; clkt->div; clkt++)27 if (clkt->val == val)28 return clkt->div;29 return 0;30}31 32static void _setup_mask(struct clk_omap_divider *divider)33{34 u16 mask;35 u32 max_val;36 const struct clk_div_table *clkt;37 38 if (divider->table) {39 max_val = 0;40 41 for (clkt = divider->table; clkt->div; clkt++)42 if (clkt->val > max_val)43 max_val = clkt->val;44 } else {45 max_val = divider->max;46 47 if (!(divider->flags & CLK_DIVIDER_ONE_BASED) &&48 !(divider->flags & CLK_DIVIDER_POWER_OF_TWO))49 max_val--;50 }51 52 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)53 mask = fls(max_val) - 1;54 else55 mask = max_val;56 57 divider->mask = (1 << fls(mask)) - 1;58}59 60static unsigned int _get_div(struct clk_omap_divider *divider, unsigned int val)61{62 if (divider->flags & CLK_DIVIDER_ONE_BASED)63 return val;64 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)65 return 1 << val;66 if (divider->table)67 return _get_table_div(divider->table, val);68 return val + 1;69}70 71static unsigned int _get_table_val(const struct clk_div_table *table,72 unsigned int div)73{74 const struct clk_div_table *clkt;75 76 for (clkt = table; clkt->div; clkt++)77 if (clkt->div == div)78 return clkt->val;79 return 0;80}81 82static unsigned int _get_val(struct clk_omap_divider *divider, u8 div)83{84 if (divider->flags & CLK_DIVIDER_ONE_BASED)85 return div;86 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)87 return __ffs(div);88 if (divider->table)89 return _get_table_val(divider->table, div);90 return div - 1;91}92 93static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw,94 unsigned long parent_rate)95{96 struct clk_omap_divider *divider = to_clk_omap_divider(hw);97 unsigned int div, val;98 99 val = ti_clk_ll_ops->clk_readl(÷r->reg) >> divider->shift;100 val &= divider->mask;101 102 div = _get_div(divider, val);103 if (!div) {104 WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),105 "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",106 clk_hw_get_name(hw));107 return parent_rate;108 }109 110 return DIV_ROUND_UP(parent_rate, div);111}112 113/*114 * The reverse of DIV_ROUND_UP: The maximum number which115 * divided by m is r116 */117#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)118 119static bool _is_valid_table_div(const struct clk_div_table *table,120 unsigned int div)121{122 const struct clk_div_table *clkt;123 124 for (clkt = table; clkt->div; clkt++)125 if (clkt->div == div)126 return true;127 return false;128}129 130static bool _is_valid_div(struct clk_omap_divider *divider, unsigned int div)131{132 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)133 return is_power_of_2(div);134 if (divider->table)135 return _is_valid_table_div(divider->table, div);136 return true;137}138 139static int _div_round_up(const struct clk_div_table *table,140 unsigned long parent_rate, unsigned long rate)141{142 const struct clk_div_table *clkt;143 int up = INT_MAX;144 int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);145 146 for (clkt = table; clkt->div; clkt++) {147 if (clkt->div == div)148 return clkt->div;149 else if (clkt->div < div)150 continue;151 152 if ((clkt->div - div) < (up - div))153 up = clkt->div;154 }155 156 return up;157}158 159static int _div_round(const struct clk_div_table *table,160 unsigned long parent_rate, unsigned long rate)161{162 if (!table)163 return DIV_ROUND_UP(parent_rate, rate);164 165 return _div_round_up(table, parent_rate, rate);166}167 168static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,169 unsigned long *best_parent_rate)170{171 struct clk_omap_divider *divider = to_clk_omap_divider(hw);172 int i, bestdiv = 0;173 unsigned long parent_rate, best = 0, now, maxdiv;174 unsigned long parent_rate_saved = *best_parent_rate;175 176 if (!rate)177 rate = 1;178 179 maxdiv = divider->max;180 181 if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {182 parent_rate = *best_parent_rate;183 bestdiv = _div_round(divider->table, parent_rate, rate);184 bestdiv = bestdiv == 0 ? 1 : bestdiv;185 bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;186 return bestdiv;187 }188 189 /*190 * The maximum divider we can use without overflowing191 * unsigned long in rate * i below192 */193 maxdiv = min(ULONG_MAX / rate, maxdiv);194 195 for (i = 1; i <= maxdiv; i++) {196 if (!_is_valid_div(divider, i))197 continue;198 if (rate * i == parent_rate_saved) {199 /*200 * It's the most ideal case if the requested rate can be201 * divided from parent clock without needing to change202 * parent rate, so return the divider immediately.203 */204 *best_parent_rate = parent_rate_saved;205 return i;206 }207 parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),208 MULT_ROUND_UP(rate, i));209 now = DIV_ROUND_UP(parent_rate, i);210 if (now <= rate && now > best) {211 bestdiv = i;212 best = now;213 *best_parent_rate = parent_rate;214 }215 }216 217 if (!bestdiv) {218 bestdiv = divider->max;219 *best_parent_rate =220 clk_hw_round_rate(clk_hw_get_parent(hw), 1);221 }222 223 return bestdiv;224}225 226static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,227 unsigned long *prate)228{229 int div;230 div = ti_clk_divider_bestdiv(hw, rate, prate);231 232 return DIV_ROUND_UP(*prate, div);233}234 235static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,236 unsigned long parent_rate)237{238 struct clk_omap_divider *divider;239 unsigned int div, value;240 u32 val;241 242 if (!hw || !rate)243 return -EINVAL;244 245 divider = to_clk_omap_divider(hw);246 247 div = DIV_ROUND_UP(parent_rate, rate);248 249 if (div > divider->max)250 div = divider->max;251 if (div < divider->min)252 div = divider->min;253 254 value = _get_val(divider, div);255 256 val = ti_clk_ll_ops->clk_readl(÷r->reg);257 val &= ~(divider->mask << divider->shift);258 val |= value << divider->shift;259 ti_clk_ll_ops->clk_writel(val, ÷r->reg);260 261 ti_clk_latch(÷r->reg, divider->latch);262 263 return 0;264}265 266/**267 * clk_divider_save_context - Save the divider value268 * @hw: pointer struct clk_hw269 *270 * Save the divider value271 */272static int clk_divider_save_context(struct clk_hw *hw)273{274 struct clk_omap_divider *divider = to_clk_omap_divider(hw);275 u32 val;276 277 val = ti_clk_ll_ops->clk_readl(÷r->reg) >> divider->shift;278 divider->context = val & divider->mask;279 280 return 0;281}282 283/**284 * clk_divider_restore_context - restore the saved the divider value285 * @hw: pointer struct clk_hw286 *287 * Restore the saved the divider value288 */289static void clk_divider_restore_context(struct clk_hw *hw)290{291 struct clk_omap_divider *divider = to_clk_omap_divider(hw);292 u32 val;293 294 val = ti_clk_ll_ops->clk_readl(÷r->reg);295 val &= ~(divider->mask << divider->shift);296 val |= divider->context << divider->shift;297 ti_clk_ll_ops->clk_writel(val, ÷r->reg);298}299 300const struct clk_ops ti_clk_divider_ops = {301 .recalc_rate = ti_clk_divider_recalc_rate,302 .round_rate = ti_clk_divider_round_rate,303 .set_rate = ti_clk_divider_set_rate,304 .save_context = clk_divider_save_context,305 .restore_context = clk_divider_restore_context,306};307 308static struct clk *_register_divider(struct device_node *node,309 u32 flags,310 struct clk_omap_divider *div)311{312 struct clk_init_data init;313 const char *parent_name;314 const char *name;315 316 parent_name = of_clk_get_parent_name(node, 0);317 318 name = ti_dt_clk_name(node);319 init.name = name;320 init.ops = &ti_clk_divider_ops;321 init.flags = flags;322 init.parent_names = (parent_name ? &parent_name : NULL);323 init.num_parents = (parent_name ? 1 : 0);324 325 div->hw.init = &init;326 327 /* register the clock */328 return of_ti_clk_register(node, &div->hw, name);329}330 331int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div,332 u8 flags, struct clk_omap_divider *divider)333{334 int valid_div = 0;335 int i;336 struct clk_div_table *tmp;337 u16 min_div = 0;338 339 if (!div_table) {340 divider->min = 1;341 divider->max = max_div;342 _setup_mask(divider);343 return 0;344 }345 346 i = 0;347 348 while (!num_dividers || i < num_dividers) {349 if (div_table[i] == -1)350 break;351 if (div_table[i])352 valid_div++;353 i++;354 }355 356 num_dividers = i;357 358 tmp = kcalloc(valid_div + 1, sizeof(*tmp), GFP_KERNEL);359 if (!tmp)360 return -ENOMEM;361 362 valid_div = 0;363 364 for (i = 0; i < num_dividers; i++)365 if (div_table[i] > 0) {366 tmp[valid_div].div = div_table[i];367 tmp[valid_div].val = i;368 valid_div++;369 if (div_table[i] > max_div)370 max_div = div_table[i];371 if (!min_div || div_table[i] < min_div)372 min_div = div_table[i];373 }374 375 divider->min = min_div;376 divider->max = max_div;377 divider->table = tmp;378 _setup_mask(divider);379 380 return 0;381}382 383static int __init ti_clk_get_div_table(struct device_node *node,384 struct clk_omap_divider *div)385{386 struct clk_div_table *table;387 const __be32 *divspec;388 u32 val;389 u32 num_div;390 u32 valid_div;391 int i;392 393 divspec = of_get_property(node, "ti,dividers", &num_div);394 395 if (!divspec)396 return 0;397 398 num_div /= 4;399 400 valid_div = 0;401 402 /* Determine required size for divider table */403 for (i = 0; i < num_div; i++) {404 of_property_read_u32_index(node, "ti,dividers", i, &val);405 if (val)406 valid_div++;407 }408 409 if (!valid_div) {410 pr_err("no valid dividers for %pOFn table\n", node);411 return -EINVAL;412 }413 414 table = kcalloc(valid_div + 1, sizeof(*table), GFP_KERNEL);415 if (!table)416 return -ENOMEM;417 418 valid_div = 0;419 420 for (i = 0; i < num_div; i++) {421 of_property_read_u32_index(node, "ti,dividers", i, &val);422 if (val) {423 table[valid_div].div = val;424 table[valid_div].val = i;425 valid_div++;426 }427 }428 429 div->table = table;430 431 return 0;432}433 434static int _populate_divider_min_max(struct device_node *node,435 struct clk_omap_divider *divider)436{437 u32 min_div = 0;438 u32 max_div = 0;439 u32 val;440 const struct clk_div_table *clkt;441 442 if (!divider->table) {443 /* Clk divider table not provided, determine min/max divs */444 if (of_property_read_u32(node, "ti,min-div", &min_div))445 min_div = 1;446 447 if (of_property_read_u32(node, "ti,max-div", &max_div)) {448 pr_err("no max-div for %pOFn!\n", node);449 return -EINVAL;450 }451 } else {452 453 for (clkt = divider->table; clkt->div; clkt++) {454 val = clkt->div;455 if (val > max_div)456 max_div = val;457 if (!min_div || val < min_div)458 min_div = val;459 }460 }461 462 divider->min = min_div;463 divider->max = max_div;464 _setup_mask(divider);465 466 return 0;467}468 469static int __init ti_clk_divider_populate(struct device_node *node,470 struct clk_omap_divider *div,471 u32 *flags)472{473 u32 val;474 int ret;475 476 ret = ti_clk_get_reg_addr(node, 0, &div->reg);477 if (ret)478 return ret;479 480 div->shift = div->reg.bit;481 482 if (!of_property_read_u32(node, "ti,latch-bit", &val))483 div->latch = val;484 else485 div->latch = -EINVAL;486 487 *flags = 0;488 div->flags = 0;489 490 if (of_property_read_bool(node, "ti,index-starts-at-one"))491 div->flags |= CLK_DIVIDER_ONE_BASED;492 493 if (of_property_read_bool(node, "ti,index-power-of-two"))494 div->flags |= CLK_DIVIDER_POWER_OF_TWO;495 496 if (of_property_read_bool(node, "ti,set-rate-parent"))497 *flags |= CLK_SET_RATE_PARENT;498 499 ret = ti_clk_get_div_table(node, div);500 if (ret)501 return ret;502 503 return _populate_divider_min_max(node, div);504}505 506/**507 * of_ti_divider_clk_setup - Setup function for simple div rate clock508 * @node: device node for this clock509 *510 * Sets up a basic divider clock.511 */512static void __init of_ti_divider_clk_setup(struct device_node *node)513{514 struct clk *clk;515 u32 flags = 0;516 struct clk_omap_divider *div;517 518 div = kzalloc(sizeof(*div), GFP_KERNEL);519 if (!div)520 return;521 522 if (ti_clk_divider_populate(node, div, &flags))523 goto cleanup;524 525 clk = _register_divider(node, flags, div);526 if (!IS_ERR(clk)) {527 of_clk_add_provider(node, of_clk_src_simple_get, clk);528 of_ti_clk_autoidle_setup(node);529 return;530 }531 532cleanup:533 kfree(div->table);534 kfree(div);535}536CLK_OF_DECLARE(divider_clk, "ti,divider-clock", of_ti_divider_clk_setup);537 538static void __init of_ti_composite_divider_clk_setup(struct device_node *node)539{540 struct clk_omap_divider *div;541 u32 tmp;542 543 div = kzalloc(sizeof(*div), GFP_KERNEL);544 if (!div)545 return;546 547 if (ti_clk_divider_populate(node, div, &tmp))548 goto cleanup;549 550 if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER))551 return;552 553cleanup:554 kfree(div->table);555 kfree(div);556}557CLK_OF_DECLARE(ti_composite_divider_clk, "ti,composite-divider-clock",558 of_ti_composite_divider_clk_setup);559