^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2016 AmLogic, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: Michael Turquette <mturquette@baylibre.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * MultiPhase Locked Loops are outputs from a PLL with additional frequency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * scaling capabilities. MPLL rates are calculated as:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "clk-regmap.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "clk-mpll.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define SDM_DEN 16384
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define N2_MIN 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define N2_MAX 511
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static inline struct meson_clk_mpll_data *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) meson_clk_mpll_data(struct clk_regmap *clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return (struct meson_clk_mpll_data *)clk->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static long rate_from_params(unsigned long parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) unsigned int sdm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned int n2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned long divisor = (SDM_DEN * n2) + sdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (n2 < N2_MIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static void params_from_rate(unsigned long requested_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unsigned long parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) unsigned int *sdm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned int *n2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) u8 flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) uint64_t div = parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) uint64_t frac = do_div(div, requested_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) frac *= SDM_DEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (flags & CLK_MESON_MPLL_ROUND_CLOSEST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) *sdm = DIV_ROUND_CLOSEST_ULL(frac, requested_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) *sdm = DIV_ROUND_UP_ULL(frac, requested_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (*sdm == SDM_DEN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) *sdm = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) div += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (div < N2_MIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) *n2 = N2_MIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) *sdm = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) } else if (div > N2_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *n2 = N2_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) *sdm = SDM_DEN - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) *n2 = div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static unsigned long mpll_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) unsigned int sdm, n2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) long rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) sdm = meson_parm_read(clk->map, &mpll->sdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) n2 = meson_parm_read(clk->map, &mpll->n2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) rate = rate_from_params(parent_rate, sdm, n2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return rate < 0 ? 0 : rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static long mpll_round_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) unsigned long *parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) unsigned int sdm, n2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) params_from_rate(rate, *parent_rate, &sdm, &n2, mpll->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return rate_from_params(*parent_rate, sdm, n2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static int mpll_set_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) unsigned int sdm, n2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) unsigned long flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) params_from_rate(rate, parent_rate, &sdm, &n2, mpll->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (mpll->lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) spin_lock_irqsave(mpll->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) __acquire(mpll->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /* Set the fractional part */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) meson_parm_write(clk->map, &mpll->sdm, sdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* Set the integer divider part */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) meson_parm_write(clk->map, &mpll->n2, n2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (mpll->lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) spin_unlock_irqrestore(mpll->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) __release(mpll->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static int mpll_init(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (mpll->init_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) regmap_multi_reg_write(clk->map, mpll->init_regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) mpll->init_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* Enable the fractional part */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) meson_parm_write(clk->map, &mpll->sdm_en, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* Set spread spectrum if possible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (MESON_PARM_APPLICABLE(&mpll->ssen)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) unsigned int ss =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) mpll->flags & CLK_MESON_MPLL_SPREAD_SPECTRUM ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) meson_parm_write(clk->map, &mpll->ssen, ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* Set the magic misc bit if required */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (MESON_PARM_APPLICABLE(&mpll->misc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) meson_parm_write(clk->map, &mpll->misc, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) const struct clk_ops meson_clk_mpll_ro_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .recalc_rate = mpll_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .round_rate = mpll_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) EXPORT_SYMBOL_GPL(meson_clk_mpll_ro_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) const struct clk_ops meson_clk_mpll_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .recalc_rate = mpll_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .round_rate = mpll_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .set_rate = mpll_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .init = mpll_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) EXPORT_SYMBOL_GPL(meson_clk_mpll_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) MODULE_DESCRIPTION("Amlogic MPLL driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) MODULE_AUTHOR("Michael Turquette <mturquette@baylibre.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) MODULE_LICENSE("GPL v2");