.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify it |
---|
5 | | - * under the terms and conditions of the GNU General Public License, |
---|
6 | | - * version 2, as published by the Free Software Foundation. |
---|
7 | | - * |
---|
8 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
---|
9 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
10 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
11 | | - * more details. |
---|
12 | | - * |
---|
13 | | - * You should have received a copy of the GNU General Public License |
---|
14 | | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
15 | 4 | */ |
---|
16 | 5 | |
---|
17 | 6 | #include <linux/kernel.h> |
---|
.. | .. |
---|
38 | 27 | #define super_state(s) (BIT(s) << SUPER_STATE_SHIFT) |
---|
39 | 28 | #define super_state_to_src_shift(m, s) ((m->width * s)) |
---|
40 | 29 | #define super_state_to_src_mask(m) (((1 << m->width) - 1)) |
---|
| 30 | + |
---|
| 31 | +#define CCLK_SRC_PLLP_OUT0 4 |
---|
| 32 | +#define CCLK_SRC_PLLP_OUT4 5 |
---|
41 | 33 | |
---|
42 | 34 | static u8 clk_super_get_parent(struct clk_hw *hw) |
---|
43 | 35 | { |
---|
.. | .. |
---|
108 | 100 | if (index == mux->div2_index) |
---|
109 | 101 | index = mux->pllx_index; |
---|
110 | 102 | } |
---|
| 103 | + |
---|
| 104 | + /* enable PLLP branches to CPU before selecting PLLP source */ |
---|
| 105 | + if ((mux->flags & TEGRA210_CPU_CLK) && |
---|
| 106 | + (index == CCLK_SRC_PLLP_OUT0 || index == CCLK_SRC_PLLP_OUT4)) |
---|
| 107 | + tegra_clk_set_pllp_out_cpu(true); |
---|
| 108 | + |
---|
111 | 109 | val &= ~((super_state_to_src_mask(mux)) << shift); |
---|
112 | 110 | val |= (index & (super_state_to_src_mask(mux))) << shift; |
---|
113 | 111 | |
---|
114 | 112 | writel_relaxed(val, mux->reg); |
---|
115 | 113 | udelay(2); |
---|
| 114 | + |
---|
| 115 | + /* disable PLLP branches to CPU if not used */ |
---|
| 116 | + if ((mux->flags & TEGRA210_CPU_CLK) && |
---|
| 117 | + index != CCLK_SRC_PLLP_OUT0 && index != CCLK_SRC_PLLP_OUT4) |
---|
| 118 | + tegra_clk_set_pllp_out_cpu(false); |
---|
116 | 119 | |
---|
117 | 120 | out: |
---|
118 | 121 | if (mux->lock) |
---|
.. | .. |
---|
121 | 124 | return err; |
---|
122 | 125 | } |
---|
123 | 126 | |
---|
124 | | -const struct clk_ops tegra_clk_super_mux_ops = { |
---|
| 127 | +static void clk_super_mux_restore_context(struct clk_hw *hw) |
---|
| 128 | +{ |
---|
| 129 | + int parent_id; |
---|
| 130 | + |
---|
| 131 | + parent_id = clk_hw_get_parent_index(hw); |
---|
| 132 | + if (WARN_ON(parent_id < 0)) |
---|
| 133 | + return; |
---|
| 134 | + |
---|
| 135 | + clk_super_set_parent(hw, parent_id); |
---|
| 136 | +} |
---|
| 137 | + |
---|
| 138 | +static const struct clk_ops tegra_clk_super_mux_ops = { |
---|
125 | 139 | .get_parent = clk_super_get_parent, |
---|
126 | 140 | .set_parent = clk_super_set_parent, |
---|
| 141 | + .restore_context = clk_super_mux_restore_context, |
---|
127 | 142 | }; |
---|
128 | 143 | |
---|
129 | 144 | static long clk_super_round_rate(struct clk_hw *hw, unsigned long rate, |
---|
.. | .. |
---|
159 | 174 | return super->div_ops->set_rate(div_hw, rate, parent_rate); |
---|
160 | 175 | } |
---|
161 | 176 | |
---|
| 177 | +static void clk_super_restore_context(struct clk_hw *hw) |
---|
| 178 | +{ |
---|
| 179 | + struct tegra_clk_super_mux *super = to_clk_super_mux(hw); |
---|
| 180 | + struct clk_hw *div_hw = &super->frac_div.hw; |
---|
| 181 | + int parent_id; |
---|
| 182 | + |
---|
| 183 | + parent_id = clk_hw_get_parent_index(hw); |
---|
| 184 | + if (WARN_ON(parent_id < 0)) |
---|
| 185 | + return; |
---|
| 186 | + |
---|
| 187 | + super->div_ops->restore_context(div_hw); |
---|
| 188 | + clk_super_set_parent(hw, parent_id); |
---|
| 189 | +} |
---|
| 190 | + |
---|
162 | 191 | const struct clk_ops tegra_clk_super_ops = { |
---|
163 | 192 | .get_parent = clk_super_get_parent, |
---|
164 | 193 | .set_parent = clk_super_set_parent, |
---|
165 | 194 | .set_rate = clk_super_set_rate, |
---|
166 | 195 | .round_rate = clk_super_round_rate, |
---|
167 | 196 | .recalc_rate = clk_super_recalc_rate, |
---|
| 197 | + .restore_context = clk_super_restore_context, |
---|
168 | 198 | }; |
---|
169 | 199 | |
---|
170 | 200 | struct clk *tegra_clk_register_super_mux(const char *name, |
---|
.. | .. |
---|
174 | 204 | { |
---|
175 | 205 | struct tegra_clk_super_mux *super; |
---|
176 | 206 | struct clk *clk; |
---|
177 | | - struct clk_init_data init = {}; |
---|
| 207 | + struct clk_init_data init; |
---|
178 | 208 | |
---|
179 | 209 | super = kzalloc(sizeof(*super), GFP_KERNEL); |
---|
180 | 210 | if (!super) |
---|
.. | .. |
---|
210 | 240 | { |
---|
211 | 241 | struct tegra_clk_super_mux *super; |
---|
212 | 242 | struct clk *clk; |
---|
213 | | - struct clk_init_data init = {}; |
---|
| 243 | + struct clk_init_data init; |
---|
214 | 244 | |
---|
215 | 245 | super = kzalloc(sizeof(*super), GFP_KERNEL); |
---|
216 | 246 | if (!super) |
---|