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