^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2014 MundoReader S.L.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: Heiko Stuebner <heiko@sntech.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Xing Zheng <zhengxing@rock-chips.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * based on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * samsung/clk.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Copyright (c) 2013 Samsung Electronics Co., Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Copyright (c) 2013 Linaro Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Author: Thomas Abraham <thomas.ab@samsung.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/mfd/syscon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/rational.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include "clk.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * Register a clock branch.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * Most clock branches have a form like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * src1 --|--\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * |M |--[GATE]-[DIV]-
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * src2 --|--/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * sometimes without one of those components.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static struct clk *rockchip_clk_register_branch(const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) const char *const *parent_names, u8 num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) void __iomem *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) u32 *mux_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) int div_offset, u8 div_shift, u8 div_width, u8 div_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct clk_div_table *div_table, int gate_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u8 gate_shift, u8 gate_flags, unsigned long flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) spinlock_t *lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct clk_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct clk_mux *mux = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct clk_gate *gate = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct clk_divider *div = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) const struct clk_ops *mux_ops = NULL, *div_ops = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) *gate_ops = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (num_parents > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) mux = kzalloc(sizeof(*mux), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (!mux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) mux->reg = base + muxdiv_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) mux->shift = mux_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) mux->mask = BIT(mux_width) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) mux->flags = mux_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) mux->table = mux_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) mux->lock = lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) mux_ops = (mux_flags & CLK_MUX_READ_ONLY) ? &clk_mux_ro_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) : &clk_mux_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (gate_offset >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) gate = kzalloc(sizeof(*gate), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!gate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) goto err_gate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) gate->flags = gate_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) gate->reg = base + gate_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) gate->bit_idx = gate_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) gate->lock = lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) gate_ops = &clk_gate_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (div_width > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) div = kzalloc(sizeof(*div), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (!div) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) goto err_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) div->flags = div_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (div_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) div->reg = base + div_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) div->reg = base + muxdiv_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) div->shift = div_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) div->width = div_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) div->lock = lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) div->table = div_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) div_ops = (div_flags & CLK_DIVIDER_READ_ONLY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ? &clk_divider_ro_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) : &clk_divider_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) mux ? &mux->hw : NULL, mux_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) div ? &div->hw : NULL, div_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) gate ? &gate->hw : NULL, gate_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (IS_ERR(hw)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) kfree(div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) kfree(gate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return ERR_CAST(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return hw->clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) err_div:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) kfree(gate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) err_gate:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) kfree(mux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct rockchip_clk_frac {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct notifier_block clk_nb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct clk_fractional_divider div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct clk_gate gate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct clk_mux mux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) const struct clk_ops *mux_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) int mux_frac_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) bool rate_change_remuxed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) int rate_change_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define to_rockchip_clk_frac_nb(nb) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) container_of(nb, struct rockchip_clk_frac, clk_nb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) unsigned long event, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct clk_notifier_data *ndata = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct rockchip_clk_frac *frac = to_rockchip_clk_frac_nb(nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct clk_mux *frac_mux = &frac->mux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) __func__, event, ndata->old_rate, ndata->new_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (event == PRE_RATE_CHANGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) frac->rate_change_idx =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) frac->mux_ops->get_parent(&frac_mux->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (frac->rate_change_idx != frac->mux_frac_idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) frac->mux_ops->set_parent(&frac_mux->hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) frac->mux_frac_idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) frac->rate_change_remuxed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) } else if (event == POST_RATE_CHANGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * The POST_RATE_CHANGE notifier runs directly after the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * divider clock is set in clk_change_rate, so we'll have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * remuxed back to the original parent before clk_change_rate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * reaches the mux itself.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (frac->rate_change_remuxed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) frac->mux_ops->set_parent(&frac_mux->hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) frac->rate_change_idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) frac->rate_change_remuxed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return notifier_from_errno(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * fractional divider must set that denominator is 20 times larger than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * numerator to generate precise clock frequency.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static void rockchip_fractional_approximation(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) unsigned long rate, unsigned long *parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) unsigned long *m, unsigned long *n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct clk_fractional_divider *fd = to_clk_fd(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) unsigned long p_rate, p_parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct clk_hw *p_parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) unsigned long scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!p_parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) *parent_rate = p_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) p_parent_rate = clk_hw_get_rate(p_parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) *parent_rate = p_parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (*parent_rate < rate * 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * Fractional frequency divider to do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * integer frequency divider does not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * need 20 times the limit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (!(*parent_rate % rate)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) *m = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) *n = *parent_rate / rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) } else if (!(fd->flags & CLK_FRAC_DIVIDER_NO_LIMIT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) pr_warn("%s p_rate(%ld) is low than rate(%ld)*20, use integer or half-div\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) clk_hw_get_name(hw),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) *parent_rate, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) *m = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) *n = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * Get rate closer to *parent_rate to guarantee there is no overflow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * for m and n. In the result it will be the nearest rate left shifted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * by (scale - fd->nwidth) bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) scale = fls_long(*parent_rate / rate - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (scale > fd->nwidth)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) rate <<= scale - fd->nwidth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) rational_best_approximation(rate, *parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) m, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) static struct clk *rockchip_clk_register_frac_branch(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) struct rockchip_clk_provider *ctx, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) const char *const *parent_names, u8 num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) void __iomem *base, int muxdiv_offset, u8 div_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) int gate_offset, u8 gate_shift, u8 gate_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) unsigned long flags, struct rockchip_clk_branch *child,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) spinlock_t *lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) struct clk_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct rockchip_clk_frac *frac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct clk_gate *gate = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct clk_fractional_divider *div = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) const struct clk_ops *div_ops = NULL, *gate_ops = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (muxdiv_offset < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (child && child->branch_type != branch_mux) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) pr_err("%s: fractional child clock for %s can only be a mux\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) __func__, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) frac = kzalloc(sizeof(*frac), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (!frac)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (gate_offset >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) gate = &frac->gate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) gate->flags = gate_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) gate->reg = base + gate_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) gate->bit_idx = gate_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) gate->lock = lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) gate_ops = &clk_gate_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) div = &frac->div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) div->flags = div_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) div->reg = base + muxdiv_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) div->mshift = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) div->mwidth = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) div->mmask = GENMASK(div->mwidth - 1, 0) << div->mshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) div->nshift = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) div->nwidth = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) div->nmask = GENMASK(div->nwidth - 1, 0) << div->nshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) div->lock = lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) div->approximation = rockchip_fractional_approximation;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) div_ops = &clk_fractional_divider_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) &div->hw, div_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) gate ? &gate->hw : NULL, gate_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) flags | CLK_SET_RATE_UNGATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (IS_ERR(hw)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) kfree(frac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return ERR_CAST(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (child) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) struct clk_mux *frac_mux = &frac->mux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct clk *mux_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) frac->mux_frac_idx = match_string(child->parent_names,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) child->num_parents, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) frac->mux_ops = &clk_mux_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) frac->clk_nb.notifier_call = rockchip_clk_frac_notifier_cb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) frac_mux->reg = base + child->muxdiv_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) frac_mux->shift = child->mux_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) frac_mux->mask = BIT(child->mux_width) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) frac_mux->flags = child->mux_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) if (child->mux_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) frac_mux->table = child->mux_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) frac_mux->lock = lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) frac_mux->hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) init.name = child->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) init.flags = child->flags | CLK_SET_RATE_PARENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) init.ops = frac->mux_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) init.parent_names = child->parent_names;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) init.num_parents = child->num_parents;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) mux_clk = clk_register(NULL, &frac_mux->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (IS_ERR(mux_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) kfree(frac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) return mux_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) rockchip_clk_add_lookup(ctx, mux_clk, child->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) /* notifier on the fraction divider to catch rate changes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (frac->mux_frac_idx >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) pr_debug("%s: found fractional parent in mux at pos %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) __func__, frac->mux_frac_idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) ret = clk_notifier_register(hw->clk, &frac->clk_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) pr_err("%s: failed to register clock notifier for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) __func__, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) pr_warn("%s: could not find %s as parent of %s, rate changes may not work\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) __func__, name, child->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) return hw->clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static struct clk *rockchip_clk_register_factor_branch(const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) const char *const *parent_names, u8 num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) void __iomem *base, unsigned int mult, unsigned int div,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) int gate_offset, u8 gate_shift, u8 gate_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) unsigned long flags, spinlock_t *lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) struct clk_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct clk_gate *gate = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) struct clk_fixed_factor *fix = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /* without gate, register a simple factor clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (gate_offset == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) return clk_register_fixed_factor(NULL, name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) parent_names[0], flags, mult,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) gate = kzalloc(sizeof(*gate), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (!gate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) gate->flags = gate_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) gate->reg = base + gate_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) gate->bit_idx = gate_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) gate->lock = lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) fix = kzalloc(sizeof(*fix), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (!fix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) kfree(gate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) fix->mult = mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) fix->div = div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) &fix->hw, &clk_fixed_factor_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) &gate->hw, &clk_gate_ops, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (IS_ERR(hw)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) kfree(fix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) kfree(gate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return ERR_CAST(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return hw->clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) void __iomem *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) unsigned long nr_clks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) struct rockchip_clk_provider *ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) struct clk **clk_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) ctx = kzalloc(sizeof(struct rockchip_clk_provider), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (!ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (!clk_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) goto err_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) for (i = 0; i < nr_clks; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) clk_table[i] = ERR_PTR(-ENOENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) ctx->reg_base = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) ctx->clk_data.clks = clk_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) ctx->clk_data.clk_num = nr_clks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) ctx->cru_node = np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) spin_lock_init(&ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) "rockchip,grf");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) ctx->pmugrf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) "rockchip,pmugrf");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) err_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) kfree(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) EXPORT_SYMBOL_GPL(rockchip_clk_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) void rockchip_clk_of_add_provider(struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) struct rockchip_clk_provider *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (of_clk_add_provider(np, of_clk_src_onecell_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) &ctx->clk_data))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) pr_err("%s: could not register clk provider\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) EXPORT_SYMBOL_GPL(rockchip_clk_of_add_provider);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) struct clk *clk, unsigned int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (ctx->clk_data.clks && id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) ctx->clk_data.clks[id] = clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) EXPORT_SYMBOL_GPL(rockchip_clk_add_lookup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) struct rockchip_pll_clock *list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) unsigned int nr_pll, int grf_lock_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) for (idx = 0; idx < nr_pll; idx++, list++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) clk = rockchip_clk_register_pll(ctx, list->type, list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) list->parent_names, list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) list->con_offset, grf_lock_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) list->lock_shift, list->mode_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) list->mode_shift, list->rate_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) list->flags, list->pll_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) pr_err("%s: failed to register clock %s\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) list->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) rockchip_clk_add_lookup(ctx, clk, list->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) EXPORT_SYMBOL_GPL(rockchip_clk_register_plls);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) struct rockchip_clk_branch *list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) unsigned int nr_clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) struct clk *clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) unsigned int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) for (idx = 0; idx < nr_clk; idx++, list++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) flags = list->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) /* catch simple muxes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) switch (list->branch_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) case branch_mux:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (list->mux_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) clk = clk_register_mux_table(NULL, list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) list->parent_names, list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) ctx->reg_base + list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) list->mux_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) BIT(list->mux_width) - 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) list->mux_flags, list->mux_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) clk = clk_register_mux(NULL, list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) list->parent_names, list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) ctx->reg_base + list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) list->mux_shift, list->mux_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) list->mux_flags, &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) case branch_muxgrf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) clk = rockchip_clk_register_muxgrf(list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) list->parent_names, list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) flags, ctx->grf, list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) list->mux_shift, list->mux_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) list->mux_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) case branch_muxpmugrf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) clk = rockchip_clk_register_muxgrf(list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) list->parent_names, list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) flags, ctx->pmugrf, list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) list->mux_shift, list->mux_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) list->mux_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) case branch_divider:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (list->div_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) clk = clk_register_divider_table(NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) list->name, list->parent_names[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) ctx->reg_base + list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) list->div_shift, list->div_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) list->div_flags, list->div_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) clk = clk_register_divider(NULL, list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) list->parent_names[0], flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) ctx->reg_base + list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) list->div_shift, list->div_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) list->div_flags, &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) case branch_fraction_divider:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) clk = rockchip_clk_register_frac_branch(ctx, list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) list->parent_names, list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) ctx->reg_base, list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) list->div_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) list->gate_offset, list->gate_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) list->gate_flags, flags, list->child,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) case branch_half_divider:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) clk = rockchip_clk_register_halfdiv(list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) list->parent_names, list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) ctx->reg_base, list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) list->mux_shift, list->mux_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) list->mux_flags, list->div_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) list->div_shift, list->div_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) list->div_flags, list->gate_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) list->gate_shift, list->gate_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) flags, &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) case branch_gate:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) flags |= CLK_SET_RATE_PARENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) clk = clk_register_gate(NULL, list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) list->parent_names[0], flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) ctx->reg_base + list->gate_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) list->gate_shift, list->gate_flags, &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) case branch_composite:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) clk = rockchip_clk_register_branch(list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) list->parent_names, list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) ctx->reg_base, list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) list->mux_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) list->mux_width, list->mux_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) list->mux_table, list->div_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) list->div_shift, list->div_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) list->div_flags, list->div_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) list->gate_offset, list->gate_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) list->gate_flags, flags, &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) case branch_mmc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) clk = rockchip_clk_register_mmc(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) list->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) list->parent_names, list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) ctx->reg_base + list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) list->div_shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) case branch_inverter:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) #ifdef CONFIG_ROCKCHIP_CLK_INV
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) clk = rockchip_clk_register_inverter(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) list->name, list->parent_names,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) ctx->reg_base + list->muxdiv_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) list->div_shift, list->div_flags, &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) case branch_factor:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) clk = rockchip_clk_register_factor_branch(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) list->name, list->parent_names,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) list->num_parents, ctx->reg_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) list->div_shift, list->div_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) list->gate_offset, list->gate_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) list->gate_flags, flags, &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) case branch_ddrclk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) clk = rockchip_clk_register_ddrclk(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) list->name, list->flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) list->parent_names, list->num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) list->muxdiv_offset, list->mux_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) list->mux_width, list->div_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) list->div_width, list->div_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) ctx->reg_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) /* none of the cases above matched */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (!clk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) pr_err("%s: unknown clock type %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) __func__, list->branch_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) pr_err("%s: failed to register clock %s: %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) __func__, list->name, PTR_ERR(clk));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) rockchip_clk_add_lookup(ctx, clk, list->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) EXPORT_SYMBOL_GPL(rockchip_clk_register_branches);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) unsigned int lookup_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) u8 num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) struct clk *parent, struct clk *alt_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) const struct rockchip_cpuclk_reg_data *reg_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) const struct rockchip_cpuclk_rate_table *rates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) int nrates)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) clk = rockchip_clk_register_cpuclk(name, num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) parent, alt_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) reg_data, rates, nrates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) ctx->reg_base, &ctx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) if (IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) pr_err("%s: failed to register clock %s: %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) __func__, name, PTR_ERR(clk));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) rockchip_clk_add_lookup(ctx, clk, lookup_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) void (*rk_dump_cru)(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) EXPORT_SYMBOL(rk_dump_cru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) static int rk_clk_panic(struct notifier_block *this,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) unsigned long ev, void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (rk_dump_cru)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) rk_dump_cru();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) static struct notifier_block rk_clk_panic_block = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) .notifier_call = rk_clk_panic,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) static void __iomem *rst_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) static unsigned int reg_restart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) static void (*cb_restart)(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) static int rockchip_restart_notify(struct notifier_block *this,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) unsigned long mode, void *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (cb_restart)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) cb_restart();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) writel(0xfdb9, rst_base + reg_restart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) static struct notifier_block rockchip_restart_handler = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) .notifier_call = rockchip_restart_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) .priority = 128,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) unsigned int reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) void (*cb)(void))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) rst_base = ctx->reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) reg_restart = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) cb_restart = cb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) ret = register_restart_handler(&rockchip_restart_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) pr_err("%s: cannot register restart handler, %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) __func__, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) atomic_notifier_chain_register(&panic_notifier_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) &rk_clk_panic_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) EXPORT_SYMBOL_GPL(rockchip_register_restart_notifier);