^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2016 Freescale Semiconductor, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright 2017~2018 NXP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Dong Aisheng <aisheng.dong@nxp.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/iopoll.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "clk.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * struct clk_pfdv2 - IMX PFD clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * @hw: clock source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * @reg: PFD register address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * @gate_bit: Gate bit offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * @vld_bit: Valid bit offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * @frac_off: PLL Fractional Divider offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct clk_pfdv2 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct clk_hw hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) u8 gate_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u8 vld_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u8 frac_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define CLK_PFDV2_FRAC_MASK 0x3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define LOCK_TIMEOUT_US USEC_PER_MSEC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static DEFINE_SPINLOCK(pfd_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static int clk_pfdv2_wait(struct clk_pfdv2 *pfd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return readl_poll_timeout(pfd->reg, val, val & (1 << pfd->vld_bit),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) 0, LOCK_TIMEOUT_US);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static int clk_pfdv2_enable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) spin_lock_irqsave(&pfd_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) val = readl_relaxed(pfd->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) val &= ~(1 << pfd->gate_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) writel_relaxed(val, pfd->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) spin_unlock_irqrestore(&pfd_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return clk_pfdv2_wait(pfd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static void clk_pfdv2_disable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) spin_lock_irqsave(&pfd_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) val = readl_relaxed(pfd->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) val |= (1 << pfd->gate_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) writel_relaxed(val, pfd->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) spin_unlock_irqrestore(&pfd_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) u64 tmp = parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) u8 frac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) frac = (readl_relaxed(pfd->reg) >> pfd->frac_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) & CLK_PFDV2_FRAC_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (!frac) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) clk_hw_get_name(hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) tmp *= 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) do_div(tmp, frac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static int clk_pfdv2_determine_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct clk_rate_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) unsigned long parent_rates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 480000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 528000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) req->best_parent_rate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) unsigned long best_rate = -1UL, rate = req->rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) unsigned long best_parent_rate = req->best_parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) u64 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) u8 frac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) for (i = 0; i < ARRAY_SIZE(parent_rates); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) tmp = parent_rates[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) tmp = tmp * 18 + rate / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) do_div(tmp, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) frac = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (frac < 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) frac = 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) else if (frac > 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) frac = 35;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) tmp = parent_rates[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) tmp *= 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) do_div(tmp, frac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (abs(tmp - req->rate) < abs(best_rate - req->rate)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) best_rate = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) best_parent_rate = parent_rates[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) req->best_parent_rate = best_parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) req->rate = best_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static int clk_pfdv2_is_enabled(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (readl_relaxed(pfd->reg) & (1 << pfd->gate_bit))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) u64 tmp = parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) u8 frac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (!rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /* PFD can NOT change rate without gating */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) WARN_ON(clk_pfdv2_is_enabled(hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) tmp = tmp * 18 + rate / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) do_div(tmp, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) frac = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (frac < 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) frac = 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) else if (frac > 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) frac = 35;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) spin_lock_irqsave(&pfd_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) val = readl_relaxed(pfd->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) val &= ~(CLK_PFDV2_FRAC_MASK << pfd->frac_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) val |= frac << pfd->frac_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) writel_relaxed(val, pfd->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) spin_unlock_irqrestore(&pfd_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static const struct clk_ops clk_pfdv2_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) .enable = clk_pfdv2_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) .disable = clk_pfdv2_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .recalc_rate = clk_pfdv2_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .determine_rate = clk_pfdv2_determine_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .set_rate = clk_pfdv2_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .is_enabled = clk_pfdv2_is_enabled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) void __iomem *reg, u8 idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct clk_pfdv2 *pfd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) struct clk_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) WARN_ON(idx > 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (!pfd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) pfd->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) pfd->gate_bit = (idx + 1) * 8 - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) pfd->vld_bit = pfd->gate_bit - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) pfd->frac_off = idx * 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) init.ops = &clk_pfdv2_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) init.parent_names = &parent_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) init.num_parents = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) pfd->hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) hw = &pfd->hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) ret = clk_hw_register(NULL, hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) kfree(pfd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) hw = ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }