blob: 593d76a114f991a0aa95289e89bb5f8bf6cc77ea [file] [log] [blame]
Prashant Gaikwad8f8f4842013-01-11 13:16:20 +05301/*
2 * 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 */
16
Stephen Boyd584ac4e2015-06-19 15:00:46 -070017#include <linux/clkdev.h>
Prashant Gaikwad8f8f4842013-01-11 13:16:20 +053018#include <linux/clk.h>
19#include <linux/clk-provider.h>
Mikko Perttunen4236e752017-03-02 16:16:16 +020020#include <linux/delay.h>
Prashant Gaikwad61fd2902013-01-11 13:16:26 +053021#include <linux/of.h>
22#include <linux/clk/tegra.h>
Stephen Warren6d5b9882013-11-05 17:33:17 -070023#include <linux/reset-controller.h>
Thierry Reding306a7f92014-07-17 13:17:24 +020024
25#include <soc/tegra/fuse.h>
Prashant Gaikwad8f8f4842013-01-11 13:16:20 +053026
27#include "clk.h"
28
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +030029#define CLK_OUT_ENB_L 0x010
30#define CLK_OUT_ENB_H 0x014
31#define CLK_OUT_ENB_U 0x018
32#define CLK_OUT_ENB_V 0x360
33#define CLK_OUT_ENB_W 0x364
34#define CLK_OUT_ENB_X 0x280
Thierry Reding699b4772015-03-23 10:52:45 +010035#define CLK_OUT_ENB_Y 0x298
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +030036#define CLK_OUT_ENB_SET_L 0x320
37#define CLK_OUT_ENB_CLR_L 0x324
38#define CLK_OUT_ENB_SET_H 0x328
39#define CLK_OUT_ENB_CLR_H 0x32c
40#define CLK_OUT_ENB_SET_U 0x330
41#define CLK_OUT_ENB_CLR_U 0x334
42#define CLK_OUT_ENB_SET_V 0x440
43#define CLK_OUT_ENB_CLR_V 0x444
44#define CLK_OUT_ENB_SET_W 0x448
45#define CLK_OUT_ENB_CLR_W 0x44c
46#define CLK_OUT_ENB_SET_X 0x284
47#define CLK_OUT_ENB_CLR_X 0x288
Thierry Reding699b4772015-03-23 10:52:45 +010048#define CLK_OUT_ENB_SET_Y 0x29c
49#define CLK_OUT_ENB_CLR_Y 0x2a0
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +030050
51#define RST_DEVICES_L 0x004
52#define RST_DEVICES_H 0x008
53#define RST_DEVICES_U 0x00C
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +030054#define RST_DEVICES_V 0x358
55#define RST_DEVICES_W 0x35C
56#define RST_DEVICES_X 0x28C
Thierry Reding699b4772015-03-23 10:52:45 +010057#define RST_DEVICES_Y 0x2a4
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +030058#define RST_DEVICES_SET_L 0x300
59#define RST_DEVICES_CLR_L 0x304
60#define RST_DEVICES_SET_H 0x308
61#define RST_DEVICES_CLR_H 0x30c
62#define RST_DEVICES_SET_U 0x310
63#define RST_DEVICES_CLR_U 0x314
64#define RST_DEVICES_SET_V 0x430
65#define RST_DEVICES_CLR_V 0x434
66#define RST_DEVICES_SET_W 0x438
67#define RST_DEVICES_CLR_W 0x43c
Peter De Schrijver2b239072013-09-11 17:57:37 +030068#define RST_DEVICES_SET_X 0x290
69#define RST_DEVICES_CLR_X 0x294
Thierry Reding699b4772015-03-23 10:52:45 +010070#define RST_DEVICES_SET_Y 0x2a8
71#define RST_DEVICES_CLR_Y 0x2ac
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +030072
Prashant Gaikwad61fd2902013-01-11 13:16:26 +053073/* Global data of Tegra CPU CAR ops */
Peter De Schrijver6a676fa2013-04-03 17:40:35 +030074static struct tegra_cpu_car_ops dummy_car_ops;
75struct tegra_cpu_car_ops *tegra_cpu_car_ops = &dummy_car_ops;
Prashant Gaikwad61fd2902013-01-11 13:16:26 +053076
Peter De Schrijver343a6072013-09-02 15:22:02 +030077int *periph_clk_enb_refcnt;
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +030078static int periph_banks;
Peter De Schrijver343a6072013-09-02 15:22:02 +030079static struct clk **clks;
80static int clk_num;
81static struct clk_onecell_data clk_data;
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +030082
Mikko Perttunen66b6f3d2015-05-20 09:27:05 +030083/* Handlers for SoC-specific reset lines */
84static int (*special_reset_assert)(unsigned long);
85static int (*special_reset_deassert)(unsigned long);
86static unsigned int num_special_reset;
87
Thierry Reding7e14f222015-04-20 14:38:39 +020088static const struct tegra_clk_periph_regs periph_regs[] = {
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +030089 [0] = {
90 .enb_reg = CLK_OUT_ENB_L,
91 .enb_set_reg = CLK_OUT_ENB_SET_L,
92 .enb_clr_reg = CLK_OUT_ENB_CLR_L,
93 .rst_reg = RST_DEVICES_L,
94 .rst_set_reg = RST_DEVICES_SET_L,
95 .rst_clr_reg = RST_DEVICES_CLR_L,
96 },
97 [1] = {
98 .enb_reg = CLK_OUT_ENB_H,
99 .enb_set_reg = CLK_OUT_ENB_SET_H,
100 .enb_clr_reg = CLK_OUT_ENB_CLR_H,
101 .rst_reg = RST_DEVICES_H,
102 .rst_set_reg = RST_DEVICES_SET_H,
103 .rst_clr_reg = RST_DEVICES_CLR_H,
104 },
105 [2] = {
106 .enb_reg = CLK_OUT_ENB_U,
107 .enb_set_reg = CLK_OUT_ENB_SET_U,
108 .enb_clr_reg = CLK_OUT_ENB_CLR_U,
109 .rst_reg = RST_DEVICES_U,
110 .rst_set_reg = RST_DEVICES_SET_U,
111 .rst_clr_reg = RST_DEVICES_CLR_U,
112 },
113 [3] = {
114 .enb_reg = CLK_OUT_ENB_V,
115 .enb_set_reg = CLK_OUT_ENB_SET_V,
116 .enb_clr_reg = CLK_OUT_ENB_CLR_V,
117 .rst_reg = RST_DEVICES_V,
118 .rst_set_reg = RST_DEVICES_SET_V,
119 .rst_clr_reg = RST_DEVICES_CLR_V,
120 },
121 [4] = {
122 .enb_reg = CLK_OUT_ENB_W,
123 .enb_set_reg = CLK_OUT_ENB_SET_W,
124 .enb_clr_reg = CLK_OUT_ENB_CLR_W,
125 .rst_reg = RST_DEVICES_W,
126 .rst_set_reg = RST_DEVICES_SET_W,
127 .rst_clr_reg = RST_DEVICES_CLR_W,
128 },
Peter De Schrijver2b239072013-09-11 17:57:37 +0300129 [5] = {
130 .enb_reg = CLK_OUT_ENB_X,
131 .enb_set_reg = CLK_OUT_ENB_SET_X,
132 .enb_clr_reg = CLK_OUT_ENB_CLR_X,
133 .rst_reg = RST_DEVICES_X,
134 .rst_set_reg = RST_DEVICES_SET_X,
135 .rst_clr_reg = RST_DEVICES_CLR_X,
136 },
Thierry Reding699b4772015-03-23 10:52:45 +0100137 [6] = {
138 .enb_reg = CLK_OUT_ENB_Y,
139 .enb_set_reg = CLK_OUT_ENB_SET_Y,
140 .enb_clr_reg = CLK_OUT_ENB_CLR_Y,
141 .rst_reg = RST_DEVICES_Y,
142 .rst_set_reg = RST_DEVICES_SET_Y,
143 .rst_clr_reg = RST_DEVICES_CLR_Y,
144 },
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +0300145};
146
Stephen Warren6d5b9882013-11-05 17:33:17 -0700147static void __iomem *clk_base;
148
149static int tegra_clk_rst_assert(struct reset_controller_dev *rcdev,
150 unsigned long id)
151{
152 /*
153 * If peripheral is on the APB bus then we must read the APB bus to
154 * flush the write operation in apb bus. This will avoid peripheral
155 * access after disabling clock. Since the reset driver has no
156 * knowledge of which reset IDs represent which devices, simply do
157 * this all the time.
158 */
159 tegra_read_chipid();
160
Mikko Perttunen66b6f3d2015-05-20 09:27:05 +0300161 if (id < periph_banks * 32) {
162 writel_relaxed(BIT(id % 32),
163 clk_base + periph_regs[id / 32].rst_set_reg);
164 return 0;
165 } else if (id < periph_banks * 32 + num_special_reset) {
166 return special_reset_assert(id);
167 }
Stephen Warren6d5b9882013-11-05 17:33:17 -0700168
Mikko Perttunen66b6f3d2015-05-20 09:27:05 +0300169 return -EINVAL;
Stephen Warren6d5b9882013-11-05 17:33:17 -0700170}
171
172static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev,
173 unsigned long id)
174{
Mikko Perttunen66b6f3d2015-05-20 09:27:05 +0300175 if (id < periph_banks * 32) {
176 writel_relaxed(BIT(id % 32),
177 clk_base + periph_regs[id / 32].rst_clr_reg);
178 return 0;
179 } else if (id < periph_banks * 32 + num_special_reset) {
180 return special_reset_deassert(id);
181 }
Stephen Warren6d5b9882013-11-05 17:33:17 -0700182
Mikko Perttunen66b6f3d2015-05-20 09:27:05 +0300183 return -EINVAL;
Stephen Warren6d5b9882013-11-05 17:33:17 -0700184}
185
Mikko Perttunen4236e752017-03-02 16:16:16 +0200186static int tegra_clk_rst_reset(struct reset_controller_dev *rcdev,
187 unsigned long id)
188{
189 int err;
190
191 err = tegra_clk_rst_assert(rcdev, id);
192 if (err)
193 return err;
194
195 udelay(1);
196
197 return tegra_clk_rst_deassert(rcdev, id);
198}
199
Thierry Reding7e14f222015-04-20 14:38:39 +0200200const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +0300201{
202 int reg_bank = clkid / 32;
203
204 if (reg_bank < periph_banks)
205 return &periph_regs[reg_bank];
206 else {
207 WARN_ON(1);
208 return NULL;
209 }
210}
211
Stephen Warren6d5b9882013-11-05 17:33:17 -0700212struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +0300213{
Stephen Warren6d5b9882013-11-05 17:33:17 -0700214 clk_base = regs;
215
Peter De Schrijver343a6072013-09-02 15:22:02 +0300216 if (WARN_ON(banks > ARRAY_SIZE(periph_regs)))
217 return NULL;
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +0300218
Peter De Schrijver343a6072013-09-02 15:22:02 +0300219 periph_clk_enb_refcnt = kzalloc(32 * banks *
220 sizeof(*periph_clk_enb_refcnt), GFP_KERNEL);
221 if (!periph_clk_enb_refcnt)
222 return NULL;
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +0300223
Peter De Schrijver343a6072013-09-02 15:22:02 +0300224 periph_banks = banks;
225
226 clks = kzalloc(num * sizeof(struct clk *), GFP_KERNEL);
227 if (!clks)
228 kfree(periph_clk_enb_refcnt);
229
230 clk_num = num;
231
232 return clks;
Peter De Schrijverd5ff89a2013-08-22 18:44:06 +0300233}
234
Prashant Gaikwad8f8f4842013-01-11 13:16:20 +0530235void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
236 struct clk *clks[], int clk_max)
237{
238 struct clk *clk;
239
240 for (; dup_list->clk_id < clk_max; dup_list++) {
241 clk = clks[dup_list->clk_id];
242 dup_list->lookup.clk = clk;
243 clkdev_add(&dup_list->lookup);
244 }
245}
246
247void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
248 struct clk *clks[], int clk_max)
249{
250 struct clk *clk;
251
252 for (; tbl->clk_id < clk_max; tbl++) {
253 clk = clks[tbl->clk_id];
Tomeu Vizosob9e742c2014-09-17 11:34:17 +0200254 if (IS_ERR_OR_NULL(clk)) {
255 pr_err("%s: invalid entry %ld in clks array for id %d\n",
256 __func__, PTR_ERR(clk), tbl->clk_id);
257 WARN_ON(1);
258
259 continue;
260 }
Prashant Gaikwad8f8f4842013-01-11 13:16:20 +0530261
262 if (tbl->parent_id < clk_max) {
263 struct clk *parent = clks[tbl->parent_id];
264 if (clk_set_parent(clk, parent)) {
265 pr_err("%s: Failed to set parent %s of %s\n",
266 __func__, __clk_get_name(parent),
267 __clk_get_name(clk));
268 WARN_ON(1);
269 }
270 }
271
272 if (tbl->rate)
273 if (clk_set_rate(clk, tbl->rate)) {
274 pr_err("%s: Failed to set rate %lu of %s\n",
275 __func__, tbl->rate,
276 __clk_get_name(clk));
277 WARN_ON(1);
278 }
279
280 if (tbl->state)
281 if (clk_prepare_enable(clk)) {
282 pr_err("%s: Failed to enable %s\n", __func__,
283 __clk_get_name(clk));
284 WARN_ON(1);
285 }
286 }
287}
Prashant Gaikwad61fd2902013-01-11 13:16:26 +0530288
Philipp Zabel7ba256d2016-02-25 10:45:11 +0100289static const struct reset_control_ops rst_ops = {
Stephen Warren6d5b9882013-11-05 17:33:17 -0700290 .assert = tegra_clk_rst_assert,
291 .deassert = tegra_clk_rst_deassert,
Mikko Perttunen4236e752017-03-02 16:16:16 +0200292 .reset = tegra_clk_rst_reset,
Stephen Warren6d5b9882013-11-05 17:33:17 -0700293};
294
295static struct reset_controller_dev rst_ctlr = {
296 .ops = &rst_ops,
297 .owner = THIS_MODULE,
298 .of_reset_n_cells = 1,
299};
300
Dmitry Osipenko5d797112018-05-08 19:26:06 +0300301void __init tegra_add_of_provider(struct device_node *np,
302 void *clk_src_onecell_get)
Peter De Schrijver343a6072013-09-02 15:22:02 +0300303{
304 int i;
305
306 for (i = 0; i < clk_num; i++) {
307 if (IS_ERR(clks[i])) {
308 pr_err
309 ("Tegra clk %d: register failed with %ld\n",
310 i, PTR_ERR(clks[i]));
311 }
312 if (!clks[i])
313 clks[i] = ERR_PTR(-EINVAL);
314 }
315
316 clk_data.clks = clks;
317 clk_data.clk_num = clk_num;
Dmitry Osipenko5d797112018-05-08 19:26:06 +0300318 of_clk_add_provider(np, clk_src_onecell_get, &clk_data);
Stephen Warren6d5b9882013-11-05 17:33:17 -0700319
320 rst_ctlr.of_node = np;
Mikko Perttunen66b6f3d2015-05-20 09:27:05 +0300321 rst_ctlr.nr_resets = periph_banks * 32 + num_special_reset;
Stephen Warren6d5b9882013-11-05 17:33:17 -0700322 reset_controller_register(&rst_ctlr);
Peter De Schrijver343a6072013-09-02 15:22:02 +0300323}
324
Mikko Perttunen66b6f3d2015-05-20 09:27:05 +0300325void __init tegra_init_special_resets(unsigned int num,
326 int (*assert)(unsigned long),
327 int (*deassert)(unsigned long))
328{
329 num_special_reset = num;
330 special_reset_assert = assert;
331 special_reset_deassert = deassert;
332}
333
Peter De Schrijver73d37e42013-10-09 14:47:57 +0300334void __init tegra_register_devclks(struct tegra_devclk *dev_clks, int num)
335{
336 int i;
337
338 for (i = 0; i < num; i++, dev_clks++)
339 clk_register_clkdev(clks[dev_clks->dt_id], dev_clks->con_id,
340 dev_clks->dev_id);
Peter De Schrijver9f0030c2014-06-26 18:36:13 +0300341
342 for (i = 0; i < clk_num; i++) {
343 if (!IS_ERR_OR_NULL(clks[i]))
344 clk_register_clkdev(clks[i], __clk_get_name(clks[i]),
345 "tegra-clk-debug");
346 }
Peter De Schrijver73d37e42013-10-09 14:47:57 +0300347}
348
Peter De Schrijverb8700d52013-10-14 16:47:37 +0300349struct clk ** __init tegra_lookup_dt_id(int clk_id,
350 struct tegra_clk *tegra_clk)
351{
352 if (tegra_clk[clk_id].present)
353 return &clks[tegra_clk[clk_id].dt_id];
354 else
355 return NULL;
356}
357
Stephen Warren441f1992013-03-25 13:22:24 -0600358tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
359
Peter De Schrijverd0a57bd2014-12-16 12:38:27 -0800360static int __init tegra_clocks_apply_init_table(void)
Stephen Warren441f1992013-03-25 13:22:24 -0600361{
362 if (!tegra_clk_apply_init_table)
Peter De Schrijverd0a57bd2014-12-16 12:38:27 -0800363 return 0;
Stephen Warren441f1992013-03-25 13:22:24 -0600364
365 tegra_clk_apply_init_table();
Peter De Schrijverd0a57bd2014-12-16 12:38:27 -0800366
367 return 0;
Stephen Warren441f1992013-03-25 13:22:24 -0600368}
Peter De Schrijverd0a57bd2014-12-16 12:38:27 -0800369arch_initcall(tegra_clocks_apply_init_table);