1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Based on drivers/clk/tegra/clk-emc.c
4 * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
5 *
6 * Author: Dmitry Osipenko <digetx@gmail.com>
7 * Copyright (C) 2019 GRATE-DRIVER project
8 */
9
10#define pr_fmt(fmt)	"tegra-emc-clk: " fmt
11
12#include <linux/bits.h>
13#include <linux/clk-provider.h>
14#include <linux/clk/tegra.h>
15#include <linux/err.h>
16#include <linux/io.h>
17#include <linux/kernel.h>
18#include <linux/slab.h>
19
20#include "clk.h"
21
22#define CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK	GENMASK(7, 0)
23#define CLK_SOURCE_EMC_2X_CLK_SRC_MASK		GENMASK(31, 30)
24#define CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT		30
25
26#define MC_EMC_SAME_FREQ	BIT(16)
27#define USE_PLLM_UD		BIT(29)
28
29#define EMC_SRC_PLL_M		0
30#define EMC_SRC_PLL_C		1
31#define EMC_SRC_PLL_P		2
32#define EMC_SRC_CLK_M		3
33
34static const char * const emc_parent_clk_names[] = {
35	"pll_m", "pll_c", "pll_p", "clk_m",
36};
37
38struct tegra_clk_emc {
39	struct clk_hw hw;
40	void __iomem *reg;
41	bool mc_same_freq;
42	bool want_low_jitter;
43
44	tegra20_clk_emc_round_cb *round_cb;
45	void *cb_arg;
46};
47
48static inline struct tegra_clk_emc *to_tegra_clk_emc(struct clk_hw *hw)
49{
50	return container_of(hw, struct tegra_clk_emc, hw);
51}
52
53static unsigned long emc_recalc_rate(struct clk_hw *hw,
54				     unsigned long parent_rate)
55{
56	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
57	u32 val, div;
58
59	val = readl_relaxed(emc->reg);
60	div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
61
62	return DIV_ROUND_UP(parent_rate * 2, div + 2);
63}
64
65static u8 emc_get_parent(struct clk_hw *hw)
66{
67	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
68
69	return readl_relaxed(emc->reg) >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
70}
71
72static int emc_set_parent(struct clk_hw *hw, u8 index)
73{
74	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
75	u32 val, div;
76
77	val = readl_relaxed(emc->reg);
78	val &= ~CLK_SOURCE_EMC_2X_CLK_SRC_MASK;
79	val |= index << CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
80
81	div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
82
83	if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
84		val |= USE_PLLM_UD;
85	else
86		val &= ~USE_PLLM_UD;
87
88	if (emc->mc_same_freq)
89		val |= MC_EMC_SAME_FREQ;
90	else
91		val &= ~MC_EMC_SAME_FREQ;
92
93	writel_relaxed(val, emc->reg);
94
95	fence_udelay(1, emc->reg);
96
97	return 0;
98}
99
100static int emc_set_rate(struct clk_hw *hw, unsigned long rate,
101			unsigned long parent_rate)
102{
103	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
104	unsigned int index;
105	u32 val, div;
106
107	div = div_frac_get(rate, parent_rate, 8, 1, 0);
108
109	val = readl_relaxed(emc->reg);
110	val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
111	val |= div;
112
113	index = val >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
114
115	if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
116		val |= USE_PLLM_UD;
117	else
118		val &= ~USE_PLLM_UD;
119
120	if (emc->mc_same_freq)
121		val |= MC_EMC_SAME_FREQ;
122	else
123		val &= ~MC_EMC_SAME_FREQ;
124
125	writel_relaxed(val, emc->reg);
126
127	fence_udelay(1, emc->reg);
128
129	return 0;
130}
131
132static int emc_set_rate_and_parent(struct clk_hw *hw,
133				   unsigned long rate,
134				   unsigned long parent_rate,
135				   u8 index)
136{
137	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
138	u32 val, div;
139
140	div = div_frac_get(rate, parent_rate, 8, 1, 0);
141
142	val = readl_relaxed(emc->reg);
143
144	val &= ~CLK_SOURCE_EMC_2X_CLK_SRC_MASK;
145	val |= index << CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
146
147	val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
148	val |= div;
149
150	if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
151		val |= USE_PLLM_UD;
152	else
153		val &= ~USE_PLLM_UD;
154
155	if (emc->mc_same_freq)
156		val |= MC_EMC_SAME_FREQ;
157	else
158		val &= ~MC_EMC_SAME_FREQ;
159
160	writel_relaxed(val, emc->reg);
161
162	fence_udelay(1, emc->reg);
163
164	return 0;
165}
166
167static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
168{
169	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
170	struct clk_hw *parent_hw;
171	unsigned long divided_rate;
172	unsigned long parent_rate;
173	unsigned int i;
174	long emc_rate;
175	int div;
176
177	emc_rate = emc->round_cb(req->rate, req->min_rate, req->max_rate,
178				 emc->cb_arg);
179	if (emc_rate < 0)
180		return emc_rate;
181
182	for (i = 0; i < ARRAY_SIZE(emc_parent_clk_names); i++) {
183		parent_hw = clk_hw_get_parent_by_index(hw, i);
184
185		if (req->best_parent_hw == parent_hw)
186			parent_rate = req->best_parent_rate;
187		else
188			parent_rate = clk_hw_get_rate(parent_hw);
189
190		if (emc_rate > parent_rate)
191			continue;
192
193		div = div_frac_get(emc_rate, parent_rate, 8, 1, 0);
194		divided_rate = DIV_ROUND_UP(parent_rate * 2, div + 2);
195
196		if (divided_rate != emc_rate)
197			continue;
198
199		req->best_parent_rate = parent_rate;
200		req->best_parent_hw = parent_hw;
201		req->rate = emc_rate;
202		break;
203	}
204
205	if (i == ARRAY_SIZE(emc_parent_clk_names)) {
206		pr_err_once("can't find parent for rate %lu emc_rate %lu\n",
207			    req->rate, emc_rate);
208		return -EINVAL;
209	}
210
211	return 0;
212}
213
214static const struct clk_ops tegra_clk_emc_ops = {
215	.recalc_rate = emc_recalc_rate,
216	.get_parent = emc_get_parent,
217	.set_parent = emc_set_parent,
218	.set_rate = emc_set_rate,
219	.set_rate_and_parent = emc_set_rate_and_parent,
220	.determine_rate = emc_determine_rate,
221};
222
223void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
224					void *cb_arg)
225{
226	struct clk *clk = __clk_lookup("emc");
227	struct tegra_clk_emc *emc;
228	struct clk_hw *hw;
229
230	if (clk) {
231		hw = __clk_get_hw(clk);
232		emc = to_tegra_clk_emc(hw);
233
234		emc->round_cb = round_cb;
235		emc->cb_arg = cb_arg;
236	}
237}
238
239bool tegra20_clk_emc_driver_available(struct clk_hw *emc_hw)
240{
241	return to_tegra_clk_emc(emc_hw)->round_cb != NULL;
242}
243
244struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter)
245{
246	struct tegra_clk_emc *emc;
247	struct clk_init_data init;
248	struct clk *clk;
249
250	emc = kzalloc(sizeof(*emc), GFP_KERNEL);
251	if (!emc)
252		return NULL;
253
254	/*
255	 * EMC stands for External Memory Controller.
256	 *
257	 * We don't want EMC clock to be disabled ever by gating its
258	 * parent and whatnot because system is busted immediately in that
259	 * case, hence the clock is marked as critical.
260	 */
261	init.name = "emc";
262	init.ops = &tegra_clk_emc_ops;
263	init.flags = CLK_IS_CRITICAL;
264	init.parent_names = emc_parent_clk_names;
265	init.num_parents = ARRAY_SIZE(emc_parent_clk_names);
266
267	emc->reg = ioaddr;
268	emc->hw.init = &init;
269	emc->want_low_jitter = low_jitter;
270
271	clk = clk_register(NULL, &emc->hw);
272	if (IS_ERR(clk)) {
273		kfree(emc);
274		return NULL;
275	}
276
277	return clk;
278}
279
280int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same)
281{
282	struct tegra_clk_emc *emc;
283	struct clk_hw *hw;
284
285	if (!emc_clk)
286		return -EINVAL;
287
288	hw = __clk_get_hw(emc_clk);
289	emc = to_tegra_clk_emc(hw);
290	emc->mc_same_freq = same;
291
292	return 0;
293}
294