blob: f00997eea2078b2ff5289eb4ed5579165b495d04 [file] [log] [blame]
Tony Lindgren0eecc632017-10-10 14:23:43 -07001/*
2 * ti-sysc.c - Texas Instruments sysc interconnect target driver
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/io.h>
15#include <linux/clk.h>
Tony Lindgren2c355ff2018-02-22 13:58:03 -080016#include <linux/clkdev.h>
Tony Lindgrena885f0f2018-02-22 14:03:48 -080017#include <linux/delay.h>
Tony Lindgren0eecc632017-10-10 14:23:43 -070018#include <linux/module.h>
19#include <linux/platform_device.h>
Tony Lindgrena885f0f2018-02-22 14:03:48 -080020#include <linux/pm_domain.h>
Tony Lindgren0eecc632017-10-10 14:23:43 -070021#include <linux/pm_runtime.h>
Tony Lindgren50622362018-04-16 10:20:27 -070022#include <linux/reset.h>
Tony Lindgren0eecc632017-10-10 14:23:43 -070023#include <linux/of_address.h>
24#include <linux/of_platform.h>
Tony Lindgren2c355ff2018-02-22 13:58:03 -080025#include <linux/slab.h>
Faiz Abbas596e7952018-07-09 22:18:39 +053026#include <linux/iopoll.h>
Tony Lindgren2c355ff2018-02-22 13:58:03 -080027
Tony Lindgren70a65242017-12-15 09:41:09 -080028#include <linux/platform_data/ti-sysc.h>
29
30#include <dt-bindings/bus/ti-sysc.h>
Tony Lindgren0eecc632017-10-10 14:23:43 -070031
Faiz Abbas596e7952018-07-09 22:18:39 +053032#define MAX_MODULE_SOFTRESET_WAIT 10000
33
Tony Lindgren0eecc632017-10-10 14:23:43 -070034static const char * const reg_names[] = { "rev", "sysc", "syss", };
35
36enum sysc_clocks {
37 SYSC_FCK,
38 SYSC_ICK,
Tony Lindgren09dfe582018-04-16 10:25:52 -070039 SYSC_OPTFCK0,
40 SYSC_OPTFCK1,
41 SYSC_OPTFCK2,
42 SYSC_OPTFCK3,
43 SYSC_OPTFCK4,
44 SYSC_OPTFCK5,
45 SYSC_OPTFCK6,
46 SYSC_OPTFCK7,
Tony Lindgren0eecc632017-10-10 14:23:43 -070047 SYSC_MAX_CLOCKS,
48};
49
Tony Lindgrena54275f2019-03-21 11:00:21 -070050static const char * const clock_names[SYSC_MAX_CLOCKS] = {
51 "fck", "ick", "opt0", "opt1", "opt2", "opt3", "opt4",
52 "opt5", "opt6", "opt7",
53};
Tony Lindgren0eecc632017-10-10 14:23:43 -070054
Tony Lindgrenc5a2de92017-12-15 09:41:23 -080055#define SYSC_IDLEMODE_MASK 3
56#define SYSC_CLOCKACTIVITY_MASK 3
57
Tony Lindgren0eecc632017-10-10 14:23:43 -070058/**
59 * struct sysc - TI sysc interconnect target module registers and capabilities
60 * @dev: struct device pointer
61 * @module_pa: physical address of the interconnect target module
62 * @module_size: size of the interconnect target module
63 * @module_va: virtual address of the interconnect target module
64 * @offsets: register offsets from module base
65 * @clocks: clocks used by the interconnect target module
Tony Lindgren09dfe582018-04-16 10:25:52 -070066 * @clock_roles: clock role names for the found clocks
67 * @nr_clocks: number of clocks used by the interconnect target module
Tony Lindgren0eecc632017-10-10 14:23:43 -070068 * @legacy_mode: configured for legacy mode if set
Tony Lindgren70a65242017-12-15 09:41:09 -080069 * @cap: interconnect target module capabilities
70 * @cfg: interconnect target module configuration
Tony Lindgren566a9b052017-12-15 09:41:19 -080071 * @name: name if available
72 * @revision: interconnect target module revision
Tony Lindgren62020f22018-02-22 13:59:44 -080073 * @needs_resume: runtime resume needed on resume from suspend
Tony Lindgren0eecc632017-10-10 14:23:43 -070074 */
75struct sysc {
76 struct device *dev;
77 u64 module_pa;
78 u32 module_size;
79 void __iomem *module_va;
80 int offsets[SYSC_MAX_REGS];
Tony Lindgrena3e92e72019-03-21 11:00:21 -070081 struct ti_sysc_module_data *mdata;
Tony Lindgren09dfe582018-04-16 10:25:52 -070082 struct clk **clocks;
83 const char **clock_roles;
84 int nr_clocks;
Tony Lindgren50622362018-04-16 10:20:27 -070085 struct reset_control *rsts;
Tony Lindgren0eecc632017-10-10 14:23:43 -070086 const char *legacy_mode;
Tony Lindgren70a65242017-12-15 09:41:09 -080087 const struct sysc_capabilities *cap;
88 struct sysc_config cfg;
Tony Lindgrenef70b0b2018-02-22 14:00:25 -080089 struct ti_sysc_cookie cookie;
Tony Lindgren566a9b052017-12-15 09:41:19 -080090 const char *name;
91 u32 revision;
Tony Lindgren62020f22018-02-22 13:59:44 -080092 bool enabled;
93 bool needs_resume;
Tony Lindgrena885f0f2018-02-22 14:03:48 -080094 bool child_needs_resume;
Tony Lindgren76f0f772018-02-23 08:28:45 -080095 struct delayed_work idle_work;
Tony Lindgren0eecc632017-10-10 14:23:43 -070096};
97
Tony Lindgren4014c082018-12-10 14:11:26 -080098static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
99 bool is_child);
100
Tony Lindgrenb7182b42019-03-21 11:00:21 -0700101static void sysc_write(struct sysc *ddata, int offset, u32 value)
Faiz Abbas596e7952018-07-09 22:18:39 +0530102{
Tony Lindgren5aa91292019-05-27 04:51:53 -0700103 if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) {
104 writew_relaxed(value & 0xffff, ddata->module_va + offset);
105
106 /* Only i2c revision has LO and HI register with stride of 4 */
107 if (ddata->offsets[SYSC_REVISION] >= 0 &&
108 offset == ddata->offsets[SYSC_REVISION]) {
109 u16 hi = value >> 16;
110
111 writew_relaxed(hi, ddata->module_va + offset + 4);
112 }
113
114 return;
115 }
116
Faiz Abbas596e7952018-07-09 22:18:39 +0530117 writel_relaxed(value, ddata->module_va + offset);
118}
119
Tony Lindgren566a9b052017-12-15 09:41:19 -0800120static u32 sysc_read(struct sysc *ddata, int offset)
121{
122 if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) {
123 u32 val;
124
125 val = readw_relaxed(ddata->module_va + offset);
Tony Lindgren5aa91292019-05-27 04:51:53 -0700126
127 /* Only i2c revision has LO and HI register with stride of 4 */
128 if (ddata->offsets[SYSC_REVISION] >= 0 &&
129 offset == ddata->offsets[SYSC_REVISION]) {
130 u16 tmp = readw_relaxed(ddata->module_va + offset + 4);
131
132 val |= tmp << 16;
133 }
Tony Lindgren566a9b052017-12-15 09:41:19 -0800134
135 return val;
136 }
137
138 return readl_relaxed(ddata->module_va + offset);
139}
140
Tony Lindgren09dfe582018-04-16 10:25:52 -0700141static bool sysc_opt_clks_needed(struct sysc *ddata)
142{
143 return !!(ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_NEEDED);
144}
145
Tony Lindgren0eecc632017-10-10 14:23:43 -0700146static u32 sysc_read_revision(struct sysc *ddata)
147{
Tony Lindgren566a9b052017-12-15 09:41:19 -0800148 int offset = ddata->offsets[SYSC_REVISION];
149
150 if (offset < 0)
151 return 0;
152
153 return sysc_read(ddata, offset);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700154}
155
Tony Lindgrena54275f2019-03-21 11:00:21 -0700156static int sysc_add_named_clock_from_child(struct sysc *ddata,
157 const char *name,
158 const char *optfck_name)
159{
160 struct device_node *np = ddata->dev->of_node;
161 struct device_node *child;
162 struct clk_lookup *cl;
163 struct clk *clock;
164 const char *n;
165
166 if (name)
167 n = name;
168 else
169 n = optfck_name;
170
171 /* Does the clock alias already exist? */
172 clock = of_clk_get_by_name(np, n);
173 if (!IS_ERR(clock)) {
174 clk_put(clock);
175
176 return 0;
177 }
178
179 child = of_get_next_available_child(np, NULL);
180 if (!child)
181 return -ENODEV;
182
183 clock = devm_get_clk_from_child(ddata->dev, child, name);
184 if (IS_ERR(clock))
185 return PTR_ERR(clock);
186
187 /*
188 * Use clkdev_add() instead of clkdev_alloc() to avoid the MAX_DEV_ID
189 * limit for clk_get(). If cl ever needs to be freed, it should be done
190 * with clkdev_drop().
191 */
192 cl = kcalloc(1, sizeof(*cl), GFP_KERNEL);
193 if (!cl)
194 return -ENOMEM;
195
196 cl->con_id = n;
197 cl->dev_id = dev_name(ddata->dev);
198 cl->clk = clock;
199 clkdev_add(cl);
200
201 clk_put(clock);
202
203 return 0;
204}
205
206static int sysc_init_ext_opt_clock(struct sysc *ddata, const char *name)
207{
208 const char *optfck_name;
209 int error, index;
210
211 if (ddata->nr_clocks < SYSC_OPTFCK0)
212 index = SYSC_OPTFCK0;
213 else
214 index = ddata->nr_clocks;
215
216 if (name)
217 optfck_name = name;
218 else
219 optfck_name = clock_names[index];
220
221 error = sysc_add_named_clock_from_child(ddata, name, optfck_name);
222 if (error)
223 return error;
224
225 ddata->clock_roles[index] = optfck_name;
226 ddata->nr_clocks++;
227
228 return 0;
229}
230
Tony Lindgren09dfe582018-04-16 10:25:52 -0700231static int sysc_get_one_clock(struct sysc *ddata, const char *name)
Tony Lindgren0eecc632017-10-10 14:23:43 -0700232{
Tony Lindgren09dfe582018-04-16 10:25:52 -0700233 int error, i, index = -ENODEV;
Tony Lindgren0eecc632017-10-10 14:23:43 -0700234
Tony Lindgren09dfe582018-04-16 10:25:52 -0700235 if (!strncmp(clock_names[SYSC_FCK], name, 3))
236 index = SYSC_FCK;
237 else if (!strncmp(clock_names[SYSC_ICK], name, 3))
238 index = SYSC_ICK;
239
240 if (index < 0) {
241 for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) {
Tony Lindgrenc97c8622018-05-18 07:54:44 -0700242 if (!ddata->clocks[i]) {
Tony Lindgren09dfe582018-04-16 10:25:52 -0700243 index = i;
244 break;
245 }
246 }
Tony Lindgren0eecc632017-10-10 14:23:43 -0700247 }
Tony Lindgren09dfe582018-04-16 10:25:52 -0700248
249 if (index < 0) {
250 dev_err(ddata->dev, "clock %s not added\n", name);
251 return index;
252 }
Tony Lindgren0eecc632017-10-10 14:23:43 -0700253
254 ddata->clocks[index] = devm_clk_get(ddata->dev, name);
255 if (IS_ERR(ddata->clocks[index])) {
256 if (PTR_ERR(ddata->clocks[index]) == -ENOENT)
257 return 0;
258
259 dev_err(ddata->dev, "clock get error for %s: %li\n",
260 name, PTR_ERR(ddata->clocks[index]));
261
262 return PTR_ERR(ddata->clocks[index]);
263 }
264
265 error = clk_prepare(ddata->clocks[index]);
266 if (error) {
267 dev_err(ddata->dev, "clock prepare error for %s: %i\n",
268 name, error);
269
270 return error;
271 }
272
273 return 0;
274}
275
276static int sysc_get_clocks(struct sysc *ddata)
277{
Tony Lindgren09dfe582018-04-16 10:25:52 -0700278 struct device_node *np = ddata->dev->of_node;
279 struct property *prop;
280 const char *name;
281 int nr_fck = 0, nr_ick = 0, i, error = 0;
Tony Lindgren0eecc632017-10-10 14:23:43 -0700282
Kees Cook20749052018-06-18 10:45:49 -0700283 ddata->clock_roles = devm_kcalloc(ddata->dev,
Tony Lindgren09dfe582018-04-16 10:25:52 -0700284 SYSC_MAX_CLOCKS,
Kees Cook20749052018-06-18 10:45:49 -0700285 sizeof(*ddata->clock_roles),
Tony Lindgren09dfe582018-04-16 10:25:52 -0700286 GFP_KERNEL);
287 if (!ddata->clock_roles)
288 return -ENOMEM;
289
290 of_property_for_each_string(np, "clock-names", prop, name) {
291 if (!strncmp(clock_names[SYSC_FCK], name, 3))
292 nr_fck++;
293 if (!strncmp(clock_names[SYSC_ICK], name, 3))
294 nr_ick++;
295 ddata->clock_roles[ddata->nr_clocks] = name;
296 ddata->nr_clocks++;
297 }
298
299 if (ddata->nr_clocks < 1)
300 return 0;
301
Tony Lindgrena54275f2019-03-21 11:00:21 -0700302 if ((ddata->cfg.quirks & SYSC_QUIRK_EXT_OPT_CLOCK)) {
303 error = sysc_init_ext_opt_clock(ddata, NULL);
304 if (error)
305 return error;
306 }
307
Tony Lindgren09dfe582018-04-16 10:25:52 -0700308 if (ddata->nr_clocks > SYSC_MAX_CLOCKS) {
309 dev_err(ddata->dev, "too many clocks for %pOF\n", np);
310
311 return -EINVAL;
312 }
313
314 if (nr_fck > 1 || nr_ick > 1) {
315 dev_err(ddata->dev, "max one fck and ick for %pOF\n", np);
316
317 return -EINVAL;
318 }
319
Kees Cook20749052018-06-18 10:45:49 -0700320 ddata->clocks = devm_kcalloc(ddata->dev,
321 ddata->nr_clocks, sizeof(*ddata->clocks),
Tony Lindgren09dfe582018-04-16 10:25:52 -0700322 GFP_KERNEL);
323 if (!ddata->clocks)
324 return -ENOMEM;
325
Tony Lindgren7b4f8ac2018-11-15 14:46:52 -0800326 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
327 const char *name = ddata->clock_roles[i];
328
329 if (!name)
330 continue;
331
332 error = sysc_get_one_clock(ddata, name);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700333 if (error && error != -ENOENT)
334 return error;
335 }
336
337 return 0;
338}
339
Tony Lindgrend8789702019-03-21 11:00:21 -0700340static int sysc_enable_main_clocks(struct sysc *ddata)
341{
342 struct clk *clock;
343 int i, error;
344
345 if (!ddata->clocks)
346 return 0;
347
348 for (i = 0; i < SYSC_OPTFCK0; i++) {
349 clock = ddata->clocks[i];
350
351 /* Main clocks may not have ick */
352 if (IS_ERR_OR_NULL(clock))
353 continue;
354
355 error = clk_enable(clock);
356 if (error)
357 goto err_disable;
358 }
359
360 return 0;
361
362err_disable:
363 for (i--; i >= 0; i--) {
364 clock = ddata->clocks[i];
365
366 /* Main clocks may not have ick */
367 if (IS_ERR_OR_NULL(clock))
368 continue;
369
370 clk_disable(clock);
371 }
372
373 return error;
374}
375
376static void sysc_disable_main_clocks(struct sysc *ddata)
377{
378 struct clk *clock;
379 int i;
380
381 if (!ddata->clocks)
382 return;
383
384 for (i = 0; i < SYSC_OPTFCK0; i++) {
385 clock = ddata->clocks[i];
386 if (IS_ERR_OR_NULL(clock))
387 continue;
388
389 clk_disable(clock);
390 }
391}
392
393static int sysc_enable_opt_clocks(struct sysc *ddata)
394{
395 struct clk *clock;
396 int i, error;
397
398 if (!ddata->clocks)
399 return 0;
400
401 for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) {
402 clock = ddata->clocks[i];
403
404 /* Assume no holes for opt clocks */
405 if (IS_ERR_OR_NULL(clock))
406 return 0;
407
408 error = clk_enable(clock);
409 if (error)
410 goto err_disable;
411 }
412
413 return 0;
414
415err_disable:
416 for (i--; i >= 0; i--) {
417 clock = ddata->clocks[i];
418 if (IS_ERR_OR_NULL(clock))
419 continue;
420
421 clk_disable(clock);
422 }
423
424 return error;
425}
426
427static void sysc_disable_opt_clocks(struct sysc *ddata)
428{
429 struct clk *clock;
430 int i;
431
432 if (!ddata->clocks)
433 return;
434
435 for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) {
436 clock = ddata->clocks[i];
437
438 /* Assume no holes for opt clocks */
439 if (IS_ERR_OR_NULL(clock))
440 return;
441
442 clk_disable(clock);
443 }
444}
445
Tony Lindgren2b2f7de2019-05-27 04:51:53 -0700446static void sysc_clkdm_deny_idle(struct sysc *ddata)
447{
448 struct ti_sysc_platform_data *pdata;
449
450 if (ddata->legacy_mode)
451 return;
452
453 pdata = dev_get_platdata(ddata->dev);
454 if (pdata && pdata->clkdm_deny_idle)
455 pdata->clkdm_deny_idle(ddata->dev, &ddata->cookie);
456}
457
458static void sysc_clkdm_allow_idle(struct sysc *ddata)
459{
460 struct ti_sysc_platform_data *pdata;
461
462 if (ddata->legacy_mode)
463 return;
464
465 pdata = dev_get_platdata(ddata->dev);
466 if (pdata && pdata->clkdm_allow_idle)
467 pdata->clkdm_allow_idle(ddata->dev, &ddata->cookie);
468}
469
Tony Lindgren0eecc632017-10-10 14:23:43 -0700470/**
Tony Lindgrenb11c1ea2019-03-21 11:00:21 -0700471 * sysc_init_resets - init rstctrl reset line if configured
Tony Lindgren50622362018-04-16 10:20:27 -0700472 * @ddata: device driver data
473 *
Tony Lindgrenb11c1ea2019-03-21 11:00:21 -0700474 * See sysc_rstctrl_reset_deassert().
Tony Lindgren50622362018-04-16 10:20:27 -0700475 */
476static int sysc_init_resets(struct sysc *ddata)
477{
Tony Lindgren50622362018-04-16 10:20:27 -0700478 ddata->rsts =
479 devm_reset_control_array_get_optional_exclusive(ddata->dev);
480 if (IS_ERR(ddata->rsts))
481 return PTR_ERR(ddata->rsts);
482
Tony Lindgren50622362018-04-16 10:20:27 -0700483 return 0;
484}
485
486/**
Tony Lindgren0eecc632017-10-10 14:23:43 -0700487 * sysc_parse_and_check_child_range - parses module IO region from ranges
488 * @ddata: device driver data
489 *
490 * In general we only need rev, syss, and sysc registers and not the whole
491 * module range. But we do want the offsets for these registers from the
492 * module base. This allows us to check them against the legacy hwmod
493 * platform data. Let's also check the ranges are configured properly.
494 */
495static int sysc_parse_and_check_child_range(struct sysc *ddata)
496{
497 struct device_node *np = ddata->dev->of_node;
498 const __be32 *ranges;
499 u32 nr_addr, nr_size;
500 int len, error;
501
502 ranges = of_get_property(np, "ranges", &len);
503 if (!ranges) {
504 dev_err(ddata->dev, "missing ranges for %pOF\n", np);
505
506 return -ENOENT;
507 }
508
509 len /= sizeof(*ranges);
510
511 if (len < 3) {
512 dev_err(ddata->dev, "incomplete ranges for %pOF\n", np);
513
514 return -EINVAL;
515 }
516
517 error = of_property_read_u32(np, "#address-cells", &nr_addr);
518 if (error)
519 return -ENOENT;
520
521 error = of_property_read_u32(np, "#size-cells", &nr_size);
522 if (error)
523 return -ENOENT;
524
525 if (nr_addr != 1 || nr_size != 1) {
526 dev_err(ddata->dev, "invalid ranges for %pOF\n", np);
527
528 return -EINVAL;
529 }
530
531 ranges++;
532 ddata->module_pa = of_translate_address(np, ranges++);
533 ddata->module_size = be32_to_cpup(ranges);
534
Tony Lindgren0eecc632017-10-10 14:23:43 -0700535 return 0;
536}
537
Tony Lindgren3bb37c82018-02-22 14:05:14 -0800538static struct device_node *stdout_path;
539
540static void sysc_init_stdout_path(struct sysc *ddata)
541{
542 struct device_node *np = NULL;
543 const char *uart;
544
545 if (IS_ERR(stdout_path))
546 return;
547
548 if (stdout_path)
549 return;
550
551 np = of_find_node_by_path("/chosen");
552 if (!np)
553 goto err;
554
555 uart = of_get_property(np, "stdout-path", NULL);
556 if (!uart)
557 goto err;
558
559 np = of_find_node_by_path(uart);
560 if (!np)
561 goto err;
562
563 stdout_path = np;
564
565 return;
566
567err:
568 stdout_path = ERR_PTR(-ENODEV);
569}
570
571static void sysc_check_quirk_stdout(struct sysc *ddata,
572 struct device_node *np)
573{
574 sysc_init_stdout_path(ddata);
575 if (np != stdout_path)
576 return;
577
578 ddata->cfg.quirks |= SYSC_QUIRK_NO_IDLE_ON_INIT |
579 SYSC_QUIRK_NO_RESET_ON_INIT;
580}
581
Tony Lindgren0eecc632017-10-10 14:23:43 -0700582/**
583 * sysc_check_one_child - check child configuration
584 * @ddata: device driver data
585 * @np: child device node
586 *
587 * Let's avoid messy situations where we have new interconnect target
588 * node but children have "ti,hwmods". These belong to the interconnect
589 * target node and are managed by this driver.
590 */
591static int sysc_check_one_child(struct sysc *ddata,
592 struct device_node *np)
593{
594 const char *name;
595
596 name = of_get_property(np, "ti,hwmods", NULL);
597 if (name)
598 dev_warn(ddata->dev, "really a child ti,hwmods property?");
599
Tony Lindgren3bb37c82018-02-22 14:05:14 -0800600 sysc_check_quirk_stdout(ddata, np);
Tony Lindgren4014c082018-12-10 14:11:26 -0800601 sysc_parse_dts_quirks(ddata, np, true);
Tony Lindgren3bb37c82018-02-22 14:05:14 -0800602
Tony Lindgren0eecc632017-10-10 14:23:43 -0700603 return 0;
604}
605
606static int sysc_check_children(struct sysc *ddata)
607{
608 struct device_node *child;
609 int error;
610
611 for_each_child_of_node(ddata->dev->of_node, child) {
612 error = sysc_check_one_child(ddata, child);
613 if (error)
614 return error;
615 }
616
617 return 0;
618}
619
Tony Lindgrena7199e22017-12-15 09:41:14 -0800620/*
621 * So far only I2C uses 16-bit read access with clockactivity with revision
622 * in two registers with stride of 4. We can detect this based on the rev
623 * register size to configure things far enough to be able to properly read
624 * the revision register.
625 */
626static void sysc_check_quirk_16bit(struct sysc *ddata, struct resource *res)
627{
Tony Lindgrendd57ac12018-02-22 14:09:57 -0800628 if (resource_size(res) == 8)
Tony Lindgrena7199e22017-12-15 09:41:14 -0800629 ddata->cfg.quirks |= SYSC_QUIRK_16BIT | SYSC_QUIRK_USE_CLOCKACT;
Tony Lindgrena7199e22017-12-15 09:41:14 -0800630}
631
Tony Lindgren0eecc632017-10-10 14:23:43 -0700632/**
633 * sysc_parse_one - parses the interconnect target module registers
634 * @ddata: device driver data
635 * @reg: register to parse
636 */
637static int sysc_parse_one(struct sysc *ddata, enum sysc_registers reg)
638{
639 struct resource *res;
640 const char *name;
641
642 switch (reg) {
643 case SYSC_REVISION:
644 case SYSC_SYSCONFIG:
645 case SYSC_SYSSTATUS:
646 name = reg_names[reg];
647 break;
648 default:
649 return -EINVAL;
650 }
651
652 res = platform_get_resource_byname(to_platform_device(ddata->dev),
653 IORESOURCE_MEM, name);
654 if (!res) {
Tony Lindgren0eecc632017-10-10 14:23:43 -0700655 ddata->offsets[reg] = -ENODEV;
656
657 return 0;
658 }
659
660 ddata->offsets[reg] = res->start - ddata->module_pa;
Tony Lindgrena7199e22017-12-15 09:41:14 -0800661 if (reg == SYSC_REVISION)
662 sysc_check_quirk_16bit(ddata, res);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700663
664 return 0;
665}
666
667static int sysc_parse_registers(struct sysc *ddata)
668{
669 int i, error;
670
671 for (i = 0; i < SYSC_MAX_REGS; i++) {
672 error = sysc_parse_one(ddata, i);
673 if (error)
674 return error;
675 }
676
677 return 0;
678}
679
680/**
681 * sysc_check_registers - check for misconfigured register overlaps
682 * @ddata: device driver data
683 */
684static int sysc_check_registers(struct sysc *ddata)
685{
686 int i, j, nr_regs = 0, nr_matches = 0;
687
688 for (i = 0; i < SYSC_MAX_REGS; i++) {
689 if (ddata->offsets[i] < 0)
690 continue;
691
692 if (ddata->offsets[i] > (ddata->module_size - 4)) {
693 dev_err(ddata->dev, "register outside module range");
694
695 return -EINVAL;
696 }
697
698 for (j = 0; j < SYSC_MAX_REGS; j++) {
699 if (ddata->offsets[j] < 0)
700 continue;
701
702 if (ddata->offsets[i] == ddata->offsets[j])
703 nr_matches++;
704 }
705 nr_regs++;
706 }
707
Tony Lindgren0eecc632017-10-10 14:23:43 -0700708 if (nr_matches > nr_regs) {
709 dev_err(ddata->dev, "overlapping registers: (%i/%i)",
710 nr_regs, nr_matches);
711
712 return -EINVAL;
713 }
714
715 return 0;
716}
717
718/**
719 * syc_ioremap - ioremap register space for the interconnect target module
Tony Lindgren0ef8e3b2018-08-08 01:07:05 -0700720 * @ddata: device driver data
Tony Lindgren0eecc632017-10-10 14:23:43 -0700721 *
722 * Note that the interconnect target module registers can be anywhere
Tony Lindgren0ef8e3b2018-08-08 01:07:05 -0700723 * within the interconnect target module range. For example, SGX has
724 * them at offset 0x1fc00 in the 32MB module address space. And cpsw
725 * has them at offset 0x1200 in the CPSW_WR child. Usually the
726 * the interconnect target module registers are at the beginning of
727 * the module range though.
Tony Lindgren0eecc632017-10-10 14:23:43 -0700728 */
729static int sysc_ioremap(struct sysc *ddata)
730{
Tony Lindgren0ef8e3b2018-08-08 01:07:05 -0700731 int size;
Tony Lindgren0eecc632017-10-10 14:23:43 -0700732
Tony Lindgrene4f50c82019-05-01 14:24:57 -0700733 if (ddata->offsets[SYSC_REVISION] < 0 &&
734 ddata->offsets[SYSC_SYSCONFIG] < 0 &&
735 ddata->offsets[SYSC_SYSSTATUS] < 0) {
736 size = ddata->module_size;
737 } else {
738 size = max3(ddata->offsets[SYSC_REVISION],
739 ddata->offsets[SYSC_SYSCONFIG],
740 ddata->offsets[SYSC_SYSSTATUS]);
Tony Lindgren0ef8e3b2018-08-08 01:07:05 -0700741
Tony Lindgrene4f50c82019-05-01 14:24:57 -0700742 if ((size + sizeof(u32)) > ddata->module_size)
743 return -EINVAL;
744 }
Tony Lindgren0eecc632017-10-10 14:23:43 -0700745
Tony Lindgren0eecc632017-10-10 14:23:43 -0700746 ddata->module_va = devm_ioremap(ddata->dev,
747 ddata->module_pa,
Tony Lindgren0ef8e3b2018-08-08 01:07:05 -0700748 size + sizeof(u32));
Tony Lindgren0eecc632017-10-10 14:23:43 -0700749 if (!ddata->module_va)
750 return -EIO;
751
752 return 0;
753}
754
755/**
756 * sysc_map_and_check_registers - ioremap and check device registers
757 * @ddata: device driver data
758 */
759static int sysc_map_and_check_registers(struct sysc *ddata)
760{
761 int error;
762
763 error = sysc_parse_and_check_child_range(ddata);
764 if (error)
765 return error;
766
767 error = sysc_check_children(ddata);
768 if (error)
769 return error;
770
771 error = sysc_parse_registers(ddata);
772 if (error)
773 return error;
774
775 error = sysc_ioremap(ddata);
776 if (error)
777 return error;
778
779 error = sysc_check_registers(ddata);
780 if (error)
781 return error;
782
783 return 0;
784}
785
786/**
787 * sysc_show_rev - read and show interconnect target module revision
788 * @bufp: buffer to print the information to
789 * @ddata: device driver data
790 */
791static int sysc_show_rev(char *bufp, struct sysc *ddata)
792{
Tony Lindgren566a9b052017-12-15 09:41:19 -0800793 int len;
Tony Lindgren0eecc632017-10-10 14:23:43 -0700794
795 if (ddata->offsets[SYSC_REVISION] < 0)
796 return sprintf(bufp, ":NA");
797
Tony Lindgren566a9b052017-12-15 09:41:19 -0800798 len = sprintf(bufp, ":%08x", ddata->revision);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700799
800 return len;
801}
802
803static int sysc_show_reg(struct sysc *ddata,
804 char *bufp, enum sysc_registers reg)
805{
806 if (ddata->offsets[reg] < 0)
807 return sprintf(bufp, ":NA");
808
809 return sprintf(bufp, ":%x", ddata->offsets[reg]);
810}
811
Tony Lindgrena885f0f2018-02-22 14:03:48 -0800812static int sysc_show_name(char *bufp, struct sysc *ddata)
813{
814 if (!ddata->name)
815 return 0;
816
817 return sprintf(bufp, ":%s", ddata->name);
818}
819
Tony Lindgren0eecc632017-10-10 14:23:43 -0700820/**
821 * sysc_show_registers - show information about interconnect target module
822 * @ddata: device driver data
823 */
824static void sysc_show_registers(struct sysc *ddata)
825{
826 char buf[128];
827 char *bufp = buf;
828 int i;
829
830 for (i = 0; i < SYSC_MAX_REGS; i++)
831 bufp += sysc_show_reg(ddata, bufp, i);
832
833 bufp += sysc_show_rev(bufp, ddata);
Tony Lindgrena885f0f2018-02-22 14:03:48 -0800834 bufp += sysc_show_name(bufp, ddata);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700835
836 dev_dbg(ddata->dev, "%llx:%x%s\n",
837 ddata->module_pa, ddata->module_size,
838 buf);
839}
840
Roger Quadrosd59b6052019-04-08 12:52:39 +0300841#define SYSC_IDLE_MASK (SYSC_NR_IDLEMODES - 1)
842
Tony Lindgren2b2f7de2019-05-27 04:51:53 -0700843/* Caller needs to manage sysc_clkdm_deny_idle() and sysc_clkdm_allow_idle() */
Roger Quadrosd59b6052019-04-08 12:52:39 +0300844static int sysc_enable_module(struct device *dev)
845{
846 struct sysc *ddata;
847 const struct sysc_regbits *regbits;
848 u32 reg, idlemodes, best_mode;
849
850 ddata = dev_get_drvdata(dev);
851 if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
852 return 0;
853
Roger Quadrosd59b6052019-04-08 12:52:39 +0300854 regbits = ddata->cap->regbits;
855 reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
856
857 /* Set SIDLE mode */
858 idlemodes = ddata->cfg.sidlemodes;
859 if (!idlemodes || regbits->sidle_shift < 0)
860 goto set_midle;
861
862 best_mode = fls(ddata->cfg.sidlemodes) - 1;
863 if (best_mode > SYSC_IDLE_MASK) {
864 dev_err(dev, "%s: invalid sidlemode\n", __func__);
865 return -EINVAL;
866 }
867
868 reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
869 reg |= best_mode << regbits->sidle_shift;
870 sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
871
872set_midle:
873 /* Set MIDLE mode */
874 idlemodes = ddata->cfg.midlemodes;
875 if (!idlemodes || regbits->midle_shift < 0)
876 return 0;
877
878 best_mode = fls(ddata->cfg.midlemodes) - 1;
879 if (best_mode > SYSC_IDLE_MASK) {
880 dev_err(dev, "%s: invalid midlemode\n", __func__);
881 return -EINVAL;
882 }
883
884 reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
885 reg |= best_mode << regbits->midle_shift;
886 sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
887
888 return 0;
889}
890
891static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode)
892{
893 if (idlemodes & BIT(SYSC_IDLE_SMART_WKUP))
894 *best_mode = SYSC_IDLE_SMART_WKUP;
895 else if (idlemodes & BIT(SYSC_IDLE_SMART))
896 *best_mode = SYSC_IDLE_SMART;
897 else if (idlemodes & SYSC_IDLE_FORCE)
898 *best_mode = SYSC_IDLE_FORCE;
899 else
900 return -EINVAL;
901
902 return 0;
903}
904
Tony Lindgren2b2f7de2019-05-27 04:51:53 -0700905/* Caller needs to manage sysc_clkdm_deny_idle() and sysc_clkdm_allow_idle() */
Roger Quadrosd59b6052019-04-08 12:52:39 +0300906static int sysc_disable_module(struct device *dev)
907{
908 struct sysc *ddata;
909 const struct sysc_regbits *regbits;
910 u32 reg, idlemodes, best_mode;
911 int ret;
912
913 ddata = dev_get_drvdata(dev);
914 if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
915 return 0;
916
Roger Quadrosd59b6052019-04-08 12:52:39 +0300917 regbits = ddata->cap->regbits;
918 reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
919
920 /* Set MIDLE mode */
921 idlemodes = ddata->cfg.midlemodes;
922 if (!idlemodes || regbits->midle_shift < 0)
923 goto set_sidle;
924
925 ret = sysc_best_idle_mode(idlemodes, &best_mode);
926 if (ret) {
927 dev_err(dev, "%s: invalid midlemode\n", __func__);
928 return ret;
929 }
930
931 reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
932 reg |= best_mode << regbits->midle_shift;
933 sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
934
935set_sidle:
936 /* Set SIDLE mode */
937 idlemodes = ddata->cfg.sidlemodes;
938 if (!idlemodes || regbits->sidle_shift < 0)
939 return 0;
940
941 ret = sysc_best_idle_mode(idlemodes, &best_mode);
942 if (ret) {
943 dev_err(dev, "%s: invalid sidlemode\n", __func__);
944 return ret;
945 }
946
947 reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
948 reg |= best_mode << regbits->sidle_shift;
949 sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
950
951 return 0;
952}
953
Tony Lindgrenff437282019-03-21 11:00:21 -0700954static int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev,
955 struct sysc *ddata)
Tony Lindgren0eecc632017-10-10 14:23:43 -0700956{
Tony Lindgrenef70b0b2018-02-22 14:00:25 -0800957 struct ti_sysc_platform_data *pdata;
Tony Lindgrenff437282019-03-21 11:00:21 -0700958 int error;
959
960 pdata = dev_get_platdata(ddata->dev);
961 if (!pdata)
962 return 0;
963
964 if (!pdata->idle_module)
965 return -ENODEV;
966
967 error = pdata->idle_module(dev, &ddata->cookie);
968 if (error)
969 dev_err(dev, "%s: could not idle: %i\n",
970 __func__, error);
971
972 return 0;
973}
974
975static int __maybe_unused sysc_runtime_resume_legacy(struct device *dev,
976 struct sysc *ddata)
977{
978 struct ti_sysc_platform_data *pdata;
979 int error;
980
981 pdata = dev_get_platdata(ddata->dev);
982 if (!pdata)
983 return 0;
984
985 if (!pdata->enable_module)
986 return -ENODEV;
987
988 error = pdata->enable_module(dev, &ddata->cookie);
989 if (error)
990 dev_err(dev, "%s: could not enable: %i\n",
991 __func__, error);
992
993 return 0;
994}
995
996static int __maybe_unused sysc_runtime_suspend(struct device *dev)
997{
Tony Lindgren0eecc632017-10-10 14:23:43 -0700998 struct sysc *ddata;
Tony Lindgrend8789702019-03-21 11:00:21 -0700999 int error = 0;
Tony Lindgren0eecc632017-10-10 14:23:43 -07001000
1001 ddata = dev_get_drvdata(dev);
1002
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08001003 if (!ddata->enabled)
Tony Lindgren0eecc632017-10-10 14:23:43 -07001004 return 0;
1005
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001006 sysc_clkdm_deny_idle(ddata);
1007
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08001008 if (ddata->legacy_mode) {
Tony Lindgrenff437282019-03-21 11:00:21 -07001009 error = sysc_runtime_suspend_legacy(dev, ddata);
Tony Lindgren93de83a2019-03-21 11:00:21 -07001010 if (error)
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001011 goto err_allow_idle;
Roger Quadrosd59b6052019-04-08 12:52:39 +03001012 } else {
1013 error = sysc_disable_module(dev);
1014 if (error)
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001015 goto err_allow_idle;
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08001016 }
1017
Tony Lindgrend8789702019-03-21 11:00:21 -07001018 sysc_disable_main_clocks(ddata);
Tony Lindgren09dfe582018-04-16 10:25:52 -07001019
Tony Lindgrend8789702019-03-21 11:00:21 -07001020 if (sysc_opt_clks_needed(ddata))
1021 sysc_disable_opt_clocks(ddata);
Tony Lindgren0eecc632017-10-10 14:23:43 -07001022
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08001023 ddata->enabled = false;
1024
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001025err_allow_idle:
1026 sysc_clkdm_allow_idle(ddata);
1027
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08001028 return error;
Tony Lindgren0eecc632017-10-10 14:23:43 -07001029}
1030
Arnd Bergmanna4a5d492017-10-13 11:25:32 +02001031static int __maybe_unused sysc_runtime_resume(struct device *dev)
Tony Lindgren0eecc632017-10-10 14:23:43 -07001032{
1033 struct sysc *ddata;
Tony Lindgrend8789702019-03-21 11:00:21 -07001034 int error = 0;
Tony Lindgren0eecc632017-10-10 14:23:43 -07001035
1036 ddata = dev_get_drvdata(dev);
1037
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08001038 if (ddata->enabled)
Tony Lindgren0eecc632017-10-10 14:23:43 -07001039 return 0;
1040
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001041 sysc_clkdm_deny_idle(ddata);
1042
Tony Lindgrend8789702019-03-21 11:00:21 -07001043 if (sysc_opt_clks_needed(ddata)) {
1044 error = sysc_enable_opt_clocks(ddata);
Tony Lindgren0eecc632017-10-10 14:23:43 -07001045 if (error)
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001046 goto err_allow_idle;
Tony Lindgren0eecc632017-10-10 14:23:43 -07001047 }
1048
Tony Lindgrend8789702019-03-21 11:00:21 -07001049 error = sysc_enable_main_clocks(ddata);
1050 if (error)
Tony Lindgren93de83a2019-03-21 11:00:21 -07001051 goto err_opt_clocks;
1052
1053 if (ddata->legacy_mode) {
1054 error = sysc_runtime_resume_legacy(dev, ddata);
1055 if (error)
1056 goto err_main_clocks;
Roger Quadrosd59b6052019-04-08 12:52:39 +03001057 } else {
1058 error = sysc_enable_module(dev);
1059 if (error)
1060 goto err_main_clocks;
Tony Lindgren93de83a2019-03-21 11:00:21 -07001061 }
Tony Lindgrend8789702019-03-21 11:00:21 -07001062
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08001063 ddata->enabled = true;
1064
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001065 sysc_clkdm_allow_idle(ddata);
1066
Tony Lindgrend8789702019-03-21 11:00:21 -07001067 return 0;
1068
1069err_main_clocks:
Tony Lindgren93de83a2019-03-21 11:00:21 -07001070 sysc_disable_main_clocks(ddata);
1071err_opt_clocks:
Tony Lindgrend8789702019-03-21 11:00:21 -07001072 if (sysc_opt_clks_needed(ddata))
1073 sysc_disable_opt_clocks(ddata);
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001074err_allow_idle:
1075 sysc_clkdm_allow_idle(ddata);
Tony Lindgrend8789702019-03-21 11:00:21 -07001076
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08001077 return error;
Tony Lindgren0eecc632017-10-10 14:23:43 -07001078}
1079
Tony Lindgrenf5e802032018-10-01 09:33:28 -07001080static int __maybe_unused sysc_noirq_suspend(struct device *dev)
Tony Lindgren62020f22018-02-22 13:59:44 -08001081{
1082 struct sysc *ddata;
1083
1084 ddata = dev_get_drvdata(dev);
1085
Tony Lindgren40d9f912018-09-24 12:16:54 -07001086 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
Tony Lindgrene7420c22018-04-16 10:26:46 -07001087 return 0;
1088
Tony Lindgrenf5e802032018-10-01 09:33:28 -07001089 return pm_runtime_force_suspend(dev);
Tony Lindgren62020f22018-02-22 13:59:44 -08001090}
1091
Tony Lindgrenf5e802032018-10-01 09:33:28 -07001092static int __maybe_unused sysc_noirq_resume(struct device *dev)
Tony Lindgren62020f22018-02-22 13:59:44 -08001093{
1094 struct sysc *ddata;
1095
1096 ddata = dev_get_drvdata(dev);
Tony Lindgrene7420c22018-04-16 10:26:46 -07001097
Tony Lindgren40d9f912018-09-24 12:16:54 -07001098 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
Tony Lindgrene7420c22018-04-16 10:26:46 -07001099 return 0;
1100
Tony Lindgrenf5e802032018-10-01 09:33:28 -07001101 return pm_runtime_force_resume(dev);
Tony Lindgrene7420c22018-04-16 10:26:46 -07001102}
1103
Tony Lindgren0eecc632017-10-10 14:23:43 -07001104static const struct dev_pm_ops sysc_pm_ops = {
Tony Lindgrene7420c22018-04-16 10:26:46 -07001105 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_noirq_suspend, sysc_noirq_resume)
Tony Lindgren0eecc632017-10-10 14:23:43 -07001106 SET_RUNTIME_PM_OPS(sysc_runtime_suspend,
1107 sysc_runtime_resume,
1108 NULL)
1109};
1110
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001111/* Module revision register based quirks */
1112struct sysc_revision_quirk {
1113 const char *name;
1114 u32 base;
1115 int rev_offset;
1116 int sysc_offset;
1117 int syss_offset;
1118 u32 revision;
1119 u32 revision_mask;
1120 u32 quirks;
1121};
1122
1123#define SYSC_QUIRK(optname, optbase, optrev, optsysc, optsyss, \
1124 optrev_val, optrevmask, optquirkmask) \
1125 { \
1126 .name = (optname), \
1127 .base = (optbase), \
1128 .rev_offset = (optrev), \
1129 .sysc_offset = (optsysc), \
1130 .syss_offset = (optsyss), \
1131 .revision = (optrev_val), \
1132 .revision_mask = (optrevmask), \
1133 .quirks = (optquirkmask), \
1134 }
1135
1136static const struct sysc_revision_quirk sysc_revision_quirks[] = {
1137 /* These drivers need to be fixed to not use pm_runtime_irq_safe() */
Tony Lindgren3a3d8022018-09-27 13:33:58 -07001138 SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffff00ff,
Tony Lindgren09dfe582018-04-16 10:25:52 -07001139 SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET),
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001140 SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000020, 0xffffffff,
1141 SYSC_QUIRK_LEGACY_IDLE),
1142 SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000030, 0xffffffff,
1143 SYSC_QUIRK_LEGACY_IDLE),
1144 SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff,
1145 SYSC_QUIRK_LEGACY_IDLE),
1146 SYSC_QUIRK("smartreflex", 0, -1, 0x24, -1, 0x00000000, 0xffffffff,
1147 SYSC_QUIRK_LEGACY_IDLE),
1148 SYSC_QUIRK("smartreflex", 0, -1, 0x38, -1, 0x00000000, 0xffffffff,
1149 SYSC_QUIRK_LEGACY_IDLE),
1150 SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff,
Tony Lindgren9bd34c62019-01-22 09:03:08 -08001151 0),
Tony Lindgren8cde5d52018-04-16 10:25:15 -07001152 /* Some timers on omap4 and later */
Tony Lindgren3a3d8022018-09-27 13:33:58 -07001153 SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x50002100, 0xffffffff,
Tony Lindgren072167d2019-01-29 07:53:47 -08001154 0),
Tony Lindgren3a3d8022018-09-27 13:33:58 -07001155 SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffff00ff,
Tony Lindgren9bd34c62019-01-22 09:03:08 -08001156 0),
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001157 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
Tony Lindgrenb4a9a7a2019-03-21 13:27:08 -07001158 SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
Tony Lindgrend708bb12018-04-16 10:25:32 -07001159 /* Uarts on omap4 and later */
Tony Lindgrenb82beef2018-09-24 12:16:59 -07001160 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
Tony Lindgrenb4a9a7a2019-03-21 13:27:08 -07001161 SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
Tony Lindgrenb82beef2018-09-24 12:16:59 -07001162 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff,
Tony Lindgrenb4a9a7a2019-03-21 13:27:08 -07001163 SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
Tony Lindgren7e27e5d2018-04-20 14:54:16 -07001164
Tony Lindgrena54275f2019-03-21 11:00:21 -07001165 /* Quirks that need to be set based on the module address */
1166 SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -1, 0x50000800, 0xffffffff,
1167 SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT |
1168 SYSC_QUIRK_SWSUP_SIDLE),
1169
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001170#ifdef DEBUG
Tony Lindgren1ba30692018-09-24 12:17:05 -07001171 SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0),
Tony Lindgrenc6eb4af2018-09-27 13:34:27 -07001172 SYSC_QUIRK("atl", 0, 0, -1, -1, 0x0a070100, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001173 SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff, 0),
Tony Lindgrenc6eb4af2018-09-27 13:34:27 -07001174 SYSC_QUIRK("cm", 0, 0, -1, -1, 0x40000301, 0xffffffff, 0),
Tony Lindgren40d9f912018-09-24 12:16:54 -07001175 SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001176 SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902,
Tony Lindgren23731ea2018-09-24 12:17:09 -07001177 0xffff00f0, 0),
1178 SYSC_QUIRK("dcan", 0, 0, -1, -1, 0xffffffff, 0xffffffff, 0),
Tony Lindgren13aad512019-03-21 11:00:21 -07001179 SYSC_QUIRK("dmic", 0, 0, 0x10, -1, 0x50010000, 0xffffffff, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001180 SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0),
1181 SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001182 SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0),
1183 SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001184 SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001185 SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
1186 SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0),
Tony Lindgrenc6eb4af2018-09-27 13:34:27 -07001187 SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, 0),
Tony Lindgren23731ea2018-09-24 12:17:09 -07001188 SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001189 SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001190 SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44307b02, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001191 SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0),
Tony Lindgrenc6eb4af2018-09-27 13:34:27 -07001192 SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffff00ff, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001193 SYSC_QUIRK("mcspi", 0, 0, 0x110, 0x114, 0x40300a0b, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001194 SYSC_QUIRK("mailbox", 0, 0, 0x10, -1, 0x00000400, 0xffffffff, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001195 SYSC_QUIRK("m3", 0, 0, -1, -1, 0x5f580105, 0x0fff0f00, 0),
Tony Lindgrenc6eb4af2018-09-27 13:34:27 -07001196 SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001197 SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0),
Tony Lindgren40d9f912018-09-24 12:16:54 -07001198 SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0),
Tony Lindgrenf0106702018-11-15 14:46:53 -08001199 SYSC_QUIRK("padconf", 0, 0, -1, -1, 0x40001100, 0xffffffff, 0),
Tony Lindgren40d9f912018-09-24 12:16:54 -07001200 SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0),
Tony Lindgren23731ea2018-09-24 12:17:09 -07001201 SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001202 SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0),
Tony Lindgren40d9f912018-09-24 12:16:54 -07001203 SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
Tony Lindgren23731ea2018-09-24 12:17:09 -07001204 SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4e8b0100, 0xffffffff, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001205 SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4f000100, 0xffffffff, 0),
Tony Lindgrenc6eb4af2018-09-27 13:34:27 -07001206 SYSC_QUIRK("scm", 0, 0, -1, -1, 0x40000900, 0xffffffff, 0),
Tony Lindgren40d9f912018-09-24 12:16:54 -07001207 SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff, 0),
Tony Lindgrenc6eb4af2018-09-27 13:34:27 -07001208 SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffff0ff0, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001209 SYSC_QUIRK("sdio", 0, 0x2fc, 0x110, 0x114, 0x31010000, 0xffffffff, 0),
Tony Lindgren40d9f912018-09-24 12:16:54 -07001210 SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001211 SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40000902, 0xffffffff, 0),
1212 SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40002903, 0xffffffff, 0),
1213 SYSC_QUIRK("spinlock", 0, 0, 0x10, -1, 0x50020000, 0xffffffff, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001214 SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -1, 0x00000020, 0xffffffff, 0),
Tony Lindgrenc6eb4af2018-09-27 13:34:27 -07001215 SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001216 SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001217 SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0),
Tony Lindgrenf0106702018-11-15 14:46:53 -08001218 SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001219 SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0),
Tony Lindgrenf0106702018-11-15 14:46:53 -08001220 SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001221 SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
1222 0xffffffff, 0),
Tony Lindgren1ba30692018-09-24 12:17:05 -07001223 SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0),
1224 SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0),
Tony Lindgrendc4c85e2018-04-16 10:26:25 -07001225#endif
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001226};
1227
Tony Lindgren42b9c5c2019-03-21 11:00:21 -07001228/*
1229 * Early quirks based on module base and register offsets only that are
1230 * needed before the module revision can be read
1231 */
1232static void sysc_init_early_quirks(struct sysc *ddata)
1233{
1234 const struct sysc_revision_quirk *q;
1235 int i;
1236
1237 for (i = 0; i < ARRAY_SIZE(sysc_revision_quirks); i++) {
1238 q = &sysc_revision_quirks[i];
1239
1240 if (!q->base)
1241 continue;
1242
1243 if (q->base != ddata->module_pa)
1244 continue;
1245
1246 if (q->rev_offset >= 0 &&
1247 q->rev_offset != ddata->offsets[SYSC_REVISION])
1248 continue;
1249
1250 if (q->sysc_offset >= 0 &&
1251 q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
1252 continue;
1253
1254 if (q->syss_offset >= 0 &&
1255 q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
1256 continue;
1257
1258 ddata->name = q->name;
1259 ddata->cfg.quirks |= q->quirks;
1260 }
1261}
1262
1263/* Quirks that also consider the revision register value */
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001264static void sysc_init_revision_quirks(struct sysc *ddata)
1265{
1266 const struct sysc_revision_quirk *q;
1267 int i;
1268
1269 for (i = 0; i < ARRAY_SIZE(sysc_revision_quirks); i++) {
1270 q = &sysc_revision_quirks[i];
1271
1272 if (q->base && q->base != ddata->module_pa)
1273 continue;
1274
1275 if (q->rev_offset >= 0 &&
1276 q->rev_offset != ddata->offsets[SYSC_REVISION])
1277 continue;
1278
1279 if (q->sysc_offset >= 0 &&
1280 q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
1281 continue;
1282
1283 if (q->syss_offset >= 0 &&
1284 q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
1285 continue;
1286
1287 if (q->revision == ddata->revision ||
1288 (q->revision & q->revision_mask) ==
1289 (ddata->revision & q->revision_mask)) {
1290 ddata->name = q->name;
1291 ddata->cfg.quirks |= q->quirks;
1292 }
1293 }
1294}
1295
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001296static int sysc_clockdomain_init(struct sysc *ddata)
1297{
1298 struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
1299 struct clk *fck = NULL, *ick = NULL;
1300 int error;
1301
1302 if (!pdata || !pdata->init_clockdomain)
1303 return 0;
1304
1305 switch (ddata->nr_clocks) {
1306 case 2:
1307 ick = ddata->clocks[SYSC_ICK];
1308 /* fallthrough */
1309 case 1:
1310 fck = ddata->clocks[SYSC_FCK];
1311 break;
1312 case 0:
1313 return 0;
1314 }
1315
1316 error = pdata->init_clockdomain(ddata->dev, fck, ick, &ddata->cookie);
1317 if (!error || error == -ENODEV)
1318 return 0;
1319
1320 return error;
1321}
1322
Tony Lindgrena3e92e72019-03-21 11:00:21 -07001323/*
1324 * Note that pdata->init_module() typically does a reset first. After
1325 * pdata->init_module() is done, PM runtime can be used for the interconnect
1326 * target module.
1327 */
1328static int sysc_legacy_init(struct sysc *ddata)
1329{
1330 struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
1331 int error;
1332
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001333 if (!pdata || !pdata->init_module)
Tony Lindgrena3e92e72019-03-21 11:00:21 -07001334 return 0;
1335
1336 error = pdata->init_module(ddata->dev, ddata->mdata, &ddata->cookie);
1337 if (error == -EEXIST)
1338 error = 0;
1339
1340 return error;
1341}
1342
Tony Lindgrenb11c1ea2019-03-21 11:00:21 -07001343/**
1344 * sysc_rstctrl_reset_deassert - deassert rstctrl reset
1345 * @ddata: device driver data
1346 * @reset: reset before deassert
1347 *
1348 * A module can have both OCP softreset control and external rstctrl.
1349 * If more complicated rstctrl resets are needed, please handle these
1350 * directly from the child device driver and map only the module reset
1351 * for the parent interconnect target module device.
1352 *
1353 * Automatic reset of the module on init can be skipped with the
1354 * "ti,no-reset-on-init" device tree property.
1355 */
1356static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset)
1357{
1358 int error;
1359
1360 if (!ddata->rsts)
1361 return 0;
1362
1363 if (reset) {
1364 error = reset_control_assert(ddata->rsts);
1365 if (error)
1366 return error;
1367 }
1368
1369 return reset_control_deassert(ddata->rsts);
1370}
1371
Faiz Abbas596e7952018-07-09 22:18:39 +05301372static int sysc_reset(struct sysc *ddata)
1373{
1374 int offset = ddata->offsets[SYSC_SYSCONFIG];
1375 int val;
1376
1377 if (ddata->legacy_mode || offset < 0 ||
1378 ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
1379 return 0;
1380
1381 /*
1382 * Currently only support reset status in sysstatus.
1383 * Warn and return error in all other cases
1384 */
1385 if (!ddata->cfg.syss_mask) {
1386 dev_err(ddata->dev, "No ti,syss-mask. Reset failed\n");
1387 return -EINVAL;
1388 }
1389
1390 val = sysc_read(ddata, offset);
1391 val |= (0x1 << ddata->cap->regbits->srst_shift);
1392 sysc_write(ddata, offset, val);
1393
1394 /* Poll on reset status */
1395 offset = ddata->offsets[SYSC_SYSSTATUS];
1396
1397 return readl_poll_timeout(ddata->module_va + offset, val,
1398 (val & ddata->cfg.syss_mask) == 0x0,
1399 100, MAX_MODULE_SOFTRESET_WAIT);
1400}
1401
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07001402/*
1403 * At this point the module is configured enough to read the revision but
1404 * module may not be completely configured yet to use PM runtime. Enable
1405 * all clocks directly during init to configure the quirks needed for PM
1406 * runtime based on the revision register.
1407 */
Tony Lindgren566a9b052017-12-15 09:41:19 -08001408static int sysc_init_module(struct sysc *ddata)
1409{
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07001410 int error = 0;
1411 bool manage_clocks = true;
Tony Lindgrenb11c1ea2019-03-21 11:00:21 -07001412 bool reset = true;
1413
1414 if (ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
1415 reset = false;
1416
1417 error = sysc_rstctrl_reset_deassert(ddata, reset);
1418 if (error)
1419 return error;
Tony Lindgren566a9b052017-12-15 09:41:19 -08001420
Tony Lindgren386cb762019-03-22 07:49:30 -07001421 if (ddata->cfg.quirks &
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07001422 (SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT))
1423 manage_clocks = false;
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001424
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001425 error = sysc_clockdomain_init(ddata);
1426 if (error)
1427 return error;
1428
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07001429 if (manage_clocks) {
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001430 sysc_clkdm_deny_idle(ddata);
1431
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07001432 error = sysc_enable_opt_clocks(ddata);
1433 if (error)
1434 return error;
Tony Lindgren566a9b052017-12-15 09:41:19 -08001435
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07001436 error = sysc_enable_main_clocks(ddata);
1437 if (error)
1438 goto err_opt_clocks;
Faiz Abbas596e7952018-07-09 22:18:39 +05301439 }
1440
Tony Lindgren566a9b052017-12-15 09:41:19 -08001441 ddata->revision = sysc_read_revision(ddata);
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001442 sysc_init_revision_quirks(ddata);
1443
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001444 if (ddata->legacy_mode) {
1445 error = sysc_legacy_init(ddata);
1446 if (error)
1447 goto err_main_clocks;
1448 }
1449
1450 if (!ddata->legacy_mode && manage_clocks) {
1451 error = sysc_enable_module(ddata->dev);
1452 if (error)
1453 goto err_main_clocks;
1454 }
Tony Lindgrena3e92e72019-03-21 11:00:21 -07001455
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07001456 error = sysc_reset(ddata);
1457 if (error)
1458 dev_err(ddata->dev, "Reset failed with %d\n", error);
1459
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001460 if (!ddata->legacy_mode && manage_clocks)
1461 sysc_disable_module(ddata->dev);
1462
Tony Lindgrena3e92e72019-03-21 11:00:21 -07001463err_main_clocks:
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07001464 if (manage_clocks)
1465 sysc_disable_main_clocks(ddata);
1466err_opt_clocks:
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001467 if (manage_clocks) {
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07001468 sysc_disable_opt_clocks(ddata);
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07001469 sysc_clkdm_allow_idle(ddata);
1470 }
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07001471
1472 return error;
Tony Lindgren566a9b052017-12-15 09:41:19 -08001473}
1474
Tony Lindgrenc5a2de92017-12-15 09:41:23 -08001475static int sysc_init_sysc_mask(struct sysc *ddata)
1476{
1477 struct device_node *np = ddata->dev->of_node;
1478 int error;
1479 u32 val;
1480
1481 error = of_property_read_u32(np, "ti,sysc-mask", &val);
1482 if (error)
1483 return 0;
1484
1485 if (val)
1486 ddata->cfg.sysc_val = val & ddata->cap->sysc_mask;
1487 else
1488 ddata->cfg.sysc_val = ddata->cap->sysc_mask;
1489
1490 return 0;
1491}
1492
1493static int sysc_init_idlemode(struct sysc *ddata, u8 *idlemodes,
1494 const char *name)
1495{
1496 struct device_node *np = ddata->dev->of_node;
1497 struct property *prop;
1498 const __be32 *p;
1499 u32 val;
1500
1501 of_property_for_each_u32(np, name, prop, p, val) {
1502 if (val >= SYSC_NR_IDLEMODES) {
1503 dev_err(ddata->dev, "invalid idlemode: %i\n", val);
1504 return -EINVAL;
1505 }
1506 *idlemodes |= (1 << val);
1507 }
1508
1509 return 0;
1510}
1511
1512static int sysc_init_idlemodes(struct sysc *ddata)
1513{
1514 int error;
1515
1516 error = sysc_init_idlemode(ddata, &ddata->cfg.midlemodes,
1517 "ti,sysc-midle");
1518 if (error)
1519 return error;
1520
1521 error = sysc_init_idlemode(ddata, &ddata->cfg.sidlemodes,
1522 "ti,sysc-sidle");
1523 if (error)
1524 return error;
1525
1526 return 0;
1527}
1528
1529/*
1530 * Only some devices on omap4 and later have SYSCONFIG reset done
1531 * bit. We can detect this if there is no SYSSTATUS at all, or the
1532 * SYSTATUS bit 0 is not used. Note that some SYSSTATUS registers
1533 * have multiple bits for the child devices like OHCI and EHCI.
1534 * Depends on SYSC being parsed first.
1535 */
1536static int sysc_init_syss_mask(struct sysc *ddata)
1537{
1538 struct device_node *np = ddata->dev->of_node;
1539 int error;
1540 u32 val;
1541
1542 error = of_property_read_u32(np, "ti,syss-mask", &val);
1543 if (error) {
1544 if ((ddata->cap->type == TI_SYSC_OMAP4 ||
1545 ddata->cap->type == TI_SYSC_OMAP4_TIMER) &&
1546 (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET))
1547 ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS;
1548
1549 return 0;
1550 }
1551
1552 if (!(val & 1) && (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET))
1553 ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS;
1554
1555 ddata->cfg.syss_mask = val;
1556
1557 return 0;
1558}
1559
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001560/*
Tony Lindgren8b2830ba2018-04-16 10:26:09 -07001561 * Many child device drivers need to have fck and opt clocks available
1562 * to get the clock rate for device internal configuration etc.
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001563 */
Tony Lindgren8b2830ba2018-04-16 10:26:09 -07001564static int sysc_child_add_named_clock(struct sysc *ddata,
1565 struct device *child,
1566 const char *name)
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001567{
Tony Lindgren8b2830ba2018-04-16 10:26:09 -07001568 struct clk *clk;
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001569 struct clk_lookup *l;
Tony Lindgren8b2830ba2018-04-16 10:26:09 -07001570 int error = 0;
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001571
Tony Lindgren8b2830ba2018-04-16 10:26:09 -07001572 if (!name)
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001573 return 0;
1574
Tony Lindgren8b2830ba2018-04-16 10:26:09 -07001575 clk = clk_get(child, name);
1576 if (!IS_ERR(clk)) {
1577 clk_put(clk);
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001578
1579 return -EEXIST;
1580 }
1581
Tony Lindgren8b2830ba2018-04-16 10:26:09 -07001582 clk = clk_get(ddata->dev, name);
1583 if (IS_ERR(clk))
1584 return -ENODEV;
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001585
Tony Lindgren8b2830ba2018-04-16 10:26:09 -07001586 l = clkdev_create(clk, name, dev_name(child));
1587 if (!l)
1588 error = -ENOMEM;
1589
1590 clk_put(clk);
1591
1592 return error;
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001593}
1594
Tony Lindgren09dfe582018-04-16 10:25:52 -07001595static int sysc_child_add_clocks(struct sysc *ddata,
1596 struct device *child)
1597{
1598 int i, error;
1599
1600 for (i = 0; i < ddata->nr_clocks; i++) {
1601 error = sysc_child_add_named_clock(ddata,
1602 child,
1603 ddata->clock_roles[i]);
1604 if (error && error != -EEXIST) {
1605 dev_err(ddata->dev, "could not add child clock %s: %i\n",
1606 ddata->clock_roles[i], error);
1607
1608 return error;
1609 }
1610 }
1611
1612 return 0;
1613}
1614
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001615static struct device_type sysc_device_type = {
1616};
1617
1618static struct sysc *sysc_child_to_parent(struct device *dev)
1619{
1620 struct device *parent = dev->parent;
1621
1622 if (!parent || parent->type != &sysc_device_type)
1623 return NULL;
1624
1625 return dev_get_drvdata(parent);
1626}
1627
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001628static int __maybe_unused sysc_child_runtime_suspend(struct device *dev)
1629{
1630 struct sysc *ddata;
1631 int error;
1632
1633 ddata = sysc_child_to_parent(dev);
1634
1635 error = pm_generic_runtime_suspend(dev);
1636 if (error)
1637 return error;
1638
1639 if (!ddata->enabled)
1640 return 0;
1641
1642 return sysc_runtime_suspend(ddata->dev);
1643}
1644
1645static int __maybe_unused sysc_child_runtime_resume(struct device *dev)
1646{
1647 struct sysc *ddata;
1648 int error;
1649
1650 ddata = sysc_child_to_parent(dev);
1651
1652 if (!ddata->enabled) {
1653 error = sysc_runtime_resume(ddata->dev);
1654 if (error < 0)
1655 dev_err(ddata->dev,
1656 "%s error: %i\n", __func__, error);
1657 }
1658
1659 return pm_generic_runtime_resume(dev);
1660}
1661
1662#ifdef CONFIG_PM_SLEEP
1663static int sysc_child_suspend_noirq(struct device *dev)
1664{
1665 struct sysc *ddata;
1666 int error;
1667
1668 ddata = sysc_child_to_parent(dev);
1669
Tony Lindgrenef55f822018-04-16 10:27:15 -07001670 dev_dbg(ddata->dev, "%s %s\n", __func__,
1671 ddata->name ? ddata->name : "");
1672
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001673 error = pm_generic_suspend_noirq(dev);
Tony Lindgrenef55f822018-04-16 10:27:15 -07001674 if (error) {
1675 dev_err(dev, "%s error at %i: %i\n",
1676 __func__, __LINE__, error);
1677
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001678 return error;
Tony Lindgrenef55f822018-04-16 10:27:15 -07001679 }
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001680
1681 if (!pm_runtime_status_suspended(dev)) {
1682 error = pm_generic_runtime_suspend(dev);
Tony Lindgrenef55f822018-04-16 10:27:15 -07001683 if (error) {
Tony Lindgrenf9490782018-09-28 15:21:50 -07001684 dev_dbg(dev, "%s busy at %i: %i\n",
1685 __func__, __LINE__, error);
Tony Lindgrenef55f822018-04-16 10:27:15 -07001686
Tony Lindgren4f3530f2018-08-08 01:07:06 -07001687 return 0;
Tony Lindgrenef55f822018-04-16 10:27:15 -07001688 }
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001689
1690 error = sysc_runtime_suspend(ddata->dev);
Tony Lindgrenef55f822018-04-16 10:27:15 -07001691 if (error) {
1692 dev_err(dev, "%s error at %i: %i\n",
1693 __func__, __LINE__, error);
1694
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001695 return error;
Tony Lindgrenef55f822018-04-16 10:27:15 -07001696 }
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001697
1698 ddata->child_needs_resume = true;
1699 }
1700
1701 return 0;
1702}
1703
1704static int sysc_child_resume_noirq(struct device *dev)
1705{
1706 struct sysc *ddata;
1707 int error;
1708
1709 ddata = sysc_child_to_parent(dev);
1710
Tony Lindgrenef55f822018-04-16 10:27:15 -07001711 dev_dbg(ddata->dev, "%s %s\n", __func__,
1712 ddata->name ? ddata->name : "");
1713
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001714 if (ddata->child_needs_resume) {
1715 ddata->child_needs_resume = false;
1716
1717 error = sysc_runtime_resume(ddata->dev);
1718 if (error)
1719 dev_err(ddata->dev,
1720 "%s runtime resume error: %i\n",
1721 __func__, error);
1722
1723 error = pm_generic_runtime_resume(dev);
1724 if (error)
1725 dev_err(ddata->dev,
1726 "%s generic runtime resume: %i\n",
1727 __func__, error);
1728 }
1729
1730 return pm_generic_resume_noirq(dev);
1731}
1732#endif
1733
Tony Lindgrenb7182b42019-03-21 11:00:21 -07001734static struct dev_pm_domain sysc_child_pm_domain = {
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001735 .ops = {
1736 SET_RUNTIME_PM_OPS(sysc_child_runtime_suspend,
1737 sysc_child_runtime_resume,
1738 NULL)
1739 USE_PLATFORM_PM_SLEEP_OPS
1740 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_child_suspend_noirq,
1741 sysc_child_resume_noirq)
1742 }
1743};
1744
1745/**
1746 * sysc_legacy_idle_quirk - handle children in omap_device compatible way
1747 * @ddata: device driver data
1748 * @child: child device driver
1749 *
1750 * Allow idle for child devices as done with _od_runtime_suspend().
1751 * Otherwise many child devices will not idle because of the permanent
1752 * parent usecount set in pm_runtime_irq_safe().
1753 *
1754 * Note that the long term solution is to just modify the child device
1755 * drivers to not set pm_runtime_irq_safe() and then this can be just
1756 * dropped.
1757 */
1758static void sysc_legacy_idle_quirk(struct sysc *ddata, struct device *child)
1759{
1760 if (!ddata->legacy_mode)
1761 return;
1762
1763 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
1764 dev_pm_domain_set(child, &sysc_child_pm_domain);
1765}
1766
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001767static int sysc_notifier_call(struct notifier_block *nb,
1768 unsigned long event, void *device)
1769{
1770 struct device *dev = device;
1771 struct sysc *ddata;
1772 int error;
1773
1774 ddata = sysc_child_to_parent(dev);
1775 if (!ddata)
1776 return NOTIFY_DONE;
1777
1778 switch (event) {
1779 case BUS_NOTIFY_ADD_DEVICE:
Tony Lindgren09dfe582018-04-16 10:25:52 -07001780 error = sysc_child_add_clocks(ddata, dev);
1781 if (error)
1782 return error;
Tony Lindgrena885f0f2018-02-22 14:03:48 -08001783 sysc_legacy_idle_quirk(ddata, dev);
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001784 break;
1785 default:
1786 break;
1787 }
1788
1789 return NOTIFY_DONE;
1790}
1791
1792static struct notifier_block sysc_nb = {
1793 .notifier_call = sysc_notifier_call,
1794};
1795
Tony Lindgren566a9b052017-12-15 09:41:19 -08001796/* Device tree configured quirks */
1797struct sysc_dts_quirk {
1798 const char *name;
1799 u32 mask;
1800};
1801
1802static const struct sysc_dts_quirk sysc_dts_quirks[] = {
1803 { .name = "ti,no-idle-on-init",
1804 .mask = SYSC_QUIRK_NO_IDLE_ON_INIT, },
1805 { .name = "ti,no-reset-on-init",
1806 .mask = SYSC_QUIRK_NO_RESET_ON_INIT, },
Tony Lindgren386cb762019-03-22 07:49:30 -07001807 { .name = "ti,no-idle",
1808 .mask = SYSC_QUIRK_NO_IDLE, },
Tony Lindgren566a9b052017-12-15 09:41:19 -08001809};
1810
Tony Lindgren4014c082018-12-10 14:11:26 -08001811static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
1812 bool is_child)
Tony Lindgren566a9b052017-12-15 09:41:19 -08001813{
Tony Lindgren566a9b052017-12-15 09:41:19 -08001814 const struct property *prop;
Tony Lindgren4014c082018-12-10 14:11:26 -08001815 int i, len;
Tony Lindgren566a9b052017-12-15 09:41:19 -08001816
1817 for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) {
Tony Lindgren4014c082018-12-10 14:11:26 -08001818 const char *name = sysc_dts_quirks[i].name;
1819
1820 prop = of_get_property(np, name, &len);
Tony Lindgren566a9b052017-12-15 09:41:19 -08001821 if (!prop)
Tony Lindgrend39b6ea2018-02-15 09:18:55 -08001822 continue;
Tony Lindgren566a9b052017-12-15 09:41:19 -08001823
1824 ddata->cfg.quirks |= sysc_dts_quirks[i].mask;
Tony Lindgren4014c082018-12-10 14:11:26 -08001825 if (is_child) {
1826 dev_warn(ddata->dev,
1827 "dts flag should be at module level for %s\n",
1828 name);
1829 }
Tony Lindgren566a9b052017-12-15 09:41:19 -08001830 }
Tony Lindgren4014c082018-12-10 14:11:26 -08001831}
Tony Lindgren566a9b052017-12-15 09:41:19 -08001832
Tony Lindgren4014c082018-12-10 14:11:26 -08001833static int sysc_init_dts_quirks(struct sysc *ddata)
1834{
1835 struct device_node *np = ddata->dev->of_node;
1836 int error;
1837 u32 val;
1838
1839 ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);
1840
1841 sysc_parse_dts_quirks(ddata, np, false);
Tony Lindgren566a9b052017-12-15 09:41:19 -08001842 error = of_property_read_u32(np, "ti,sysc-delay-us", &val);
1843 if (!error) {
1844 if (val > 255) {
1845 dev_warn(ddata->dev, "bad ti,sysc-delay-us: %i\n",
1846 val);
1847 }
1848
1849 ddata->cfg.srst_udelay = (u8)val;
1850 }
1851
1852 return 0;
1853}
1854
Tony Lindgren0eecc632017-10-10 14:23:43 -07001855static void sysc_unprepare(struct sysc *ddata)
1856{
1857 int i;
1858
Tony Lindgrenaaa29bb2019-03-21 11:00:21 -07001859 if (!ddata->clocks)
1860 return;
1861
Tony Lindgren0eecc632017-10-10 14:23:43 -07001862 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
1863 if (!IS_ERR_OR_NULL(ddata->clocks[i]))
1864 clk_unprepare(ddata->clocks[i]);
1865 }
1866}
1867
Tony Lindgren70a65242017-12-15 09:41:09 -08001868/*
1869 * Common sysc register bits found on omap2, also known as type1
1870 */
1871static const struct sysc_regbits sysc_regbits_omap2 = {
1872 .dmadisable_shift = -ENODEV,
1873 .midle_shift = 12,
1874 .sidle_shift = 3,
1875 .clkact_shift = 8,
1876 .emufree_shift = 5,
1877 .enwkup_shift = 2,
1878 .srst_shift = 1,
1879 .autoidle_shift = 0,
1880};
1881
1882static const struct sysc_capabilities sysc_omap2 = {
1883 .type = TI_SYSC_OMAP2,
1884 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY | SYSC_OMAP2_EMUFREE |
1885 SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_SOFTRESET |
1886 SYSC_OMAP2_AUTOIDLE,
1887 .regbits = &sysc_regbits_omap2,
1888};
1889
1890/* All omap2 and 3 timers, and timers 1, 2 & 10 on omap 4 and 5 */
1891static const struct sysc_capabilities sysc_omap2_timer = {
1892 .type = TI_SYSC_OMAP2_TIMER,
1893 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY | SYSC_OMAP2_EMUFREE |
1894 SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_SOFTRESET |
1895 SYSC_OMAP2_AUTOIDLE,
1896 .regbits = &sysc_regbits_omap2,
1897 .mod_quirks = SYSC_QUIRK_USE_CLOCKACT,
1898};
1899
1900/*
1901 * SHAM2 (SHA1/MD5) sysc found on omap3, a variant of sysc_regbits_omap2
1902 * with different sidle position
1903 */
1904static const struct sysc_regbits sysc_regbits_omap3_sham = {
1905 .dmadisable_shift = -ENODEV,
1906 .midle_shift = -ENODEV,
1907 .sidle_shift = 4,
1908 .clkact_shift = -ENODEV,
1909 .enwkup_shift = -ENODEV,
1910 .srst_shift = 1,
1911 .autoidle_shift = 0,
1912 .emufree_shift = -ENODEV,
1913};
1914
1915static const struct sysc_capabilities sysc_omap3_sham = {
1916 .type = TI_SYSC_OMAP3_SHAM,
1917 .sysc_mask = SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE,
1918 .regbits = &sysc_regbits_omap3_sham,
1919};
1920
1921/*
1922 * AES register bits found on omap3 and later, a variant of
1923 * sysc_regbits_omap2 with different sidle position
1924 */
1925static const struct sysc_regbits sysc_regbits_omap3_aes = {
1926 .dmadisable_shift = -ENODEV,
1927 .midle_shift = -ENODEV,
1928 .sidle_shift = 6,
1929 .clkact_shift = -ENODEV,
1930 .enwkup_shift = -ENODEV,
1931 .srst_shift = 1,
1932 .autoidle_shift = 0,
1933 .emufree_shift = -ENODEV,
1934};
1935
1936static const struct sysc_capabilities sysc_omap3_aes = {
1937 .type = TI_SYSC_OMAP3_AES,
1938 .sysc_mask = SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE,
1939 .regbits = &sysc_regbits_omap3_aes,
1940};
1941
1942/*
1943 * Common sysc register bits found on omap4, also known as type2
1944 */
1945static const struct sysc_regbits sysc_regbits_omap4 = {
1946 .dmadisable_shift = 16,
1947 .midle_shift = 4,
1948 .sidle_shift = 2,
1949 .clkact_shift = -ENODEV,
1950 .enwkup_shift = -ENODEV,
1951 .emufree_shift = 1,
1952 .srst_shift = 0,
1953 .autoidle_shift = -ENODEV,
1954};
1955
1956static const struct sysc_capabilities sysc_omap4 = {
1957 .type = TI_SYSC_OMAP4,
1958 .sysc_mask = SYSC_OMAP4_DMADISABLE | SYSC_OMAP4_FREEEMU |
1959 SYSC_OMAP4_SOFTRESET,
1960 .regbits = &sysc_regbits_omap4,
1961};
1962
1963static const struct sysc_capabilities sysc_omap4_timer = {
1964 .type = TI_SYSC_OMAP4_TIMER,
1965 .sysc_mask = SYSC_OMAP4_DMADISABLE | SYSC_OMAP4_FREEEMU |
1966 SYSC_OMAP4_SOFTRESET,
1967 .regbits = &sysc_regbits_omap4,
1968};
1969
1970/*
1971 * Common sysc register bits found on omap4, also known as type3
1972 */
1973static const struct sysc_regbits sysc_regbits_omap4_simple = {
1974 .dmadisable_shift = -ENODEV,
1975 .midle_shift = 2,
1976 .sidle_shift = 0,
1977 .clkact_shift = -ENODEV,
1978 .enwkup_shift = -ENODEV,
1979 .srst_shift = -ENODEV,
1980 .emufree_shift = -ENODEV,
1981 .autoidle_shift = -ENODEV,
1982};
1983
1984static const struct sysc_capabilities sysc_omap4_simple = {
1985 .type = TI_SYSC_OMAP4_SIMPLE,
1986 .regbits = &sysc_regbits_omap4_simple,
1987};
1988
1989/*
1990 * SmartReflex sysc found on omap34xx
1991 */
1992static const struct sysc_regbits sysc_regbits_omap34xx_sr = {
1993 .dmadisable_shift = -ENODEV,
1994 .midle_shift = -ENODEV,
1995 .sidle_shift = -ENODEV,
1996 .clkact_shift = 20,
1997 .enwkup_shift = -ENODEV,
1998 .srst_shift = -ENODEV,
1999 .emufree_shift = -ENODEV,
2000 .autoidle_shift = -ENODEV,
2001};
2002
2003static const struct sysc_capabilities sysc_34xx_sr = {
2004 .type = TI_SYSC_OMAP34XX_SR,
2005 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY,
2006 .regbits = &sysc_regbits_omap34xx_sr,
Tony Lindgrena885f0f2018-02-22 14:03:48 -08002007 .mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED |
2008 SYSC_QUIRK_LEGACY_IDLE,
Tony Lindgren70a65242017-12-15 09:41:09 -08002009};
2010
2011/*
2012 * SmartReflex sysc found on omap36xx and later
2013 */
2014static const struct sysc_regbits sysc_regbits_omap36xx_sr = {
2015 .dmadisable_shift = -ENODEV,
2016 .midle_shift = -ENODEV,
2017 .sidle_shift = 24,
2018 .clkact_shift = -ENODEV,
2019 .enwkup_shift = 26,
2020 .srst_shift = -ENODEV,
2021 .emufree_shift = -ENODEV,
2022 .autoidle_shift = -ENODEV,
2023};
2024
2025static const struct sysc_capabilities sysc_36xx_sr = {
2026 .type = TI_SYSC_OMAP36XX_SR,
Tony Lindgren3267c082018-01-22 09:32:53 -08002027 .sysc_mask = SYSC_OMAP3_SR_ENAWAKEUP,
Tony Lindgren70a65242017-12-15 09:41:09 -08002028 .regbits = &sysc_regbits_omap36xx_sr,
Tony Lindgrena885f0f2018-02-22 14:03:48 -08002029 .mod_quirks = SYSC_QUIRK_UNCACHED | SYSC_QUIRK_LEGACY_IDLE,
Tony Lindgren70a65242017-12-15 09:41:09 -08002030};
2031
2032static const struct sysc_capabilities sysc_omap4_sr = {
2033 .type = TI_SYSC_OMAP4_SR,
2034 .regbits = &sysc_regbits_omap36xx_sr,
Tony Lindgrena885f0f2018-02-22 14:03:48 -08002035 .mod_quirks = SYSC_QUIRK_LEGACY_IDLE,
Tony Lindgren70a65242017-12-15 09:41:09 -08002036};
2037
2038/*
2039 * McASP register bits found on omap4 and later
2040 */
2041static const struct sysc_regbits sysc_regbits_omap4_mcasp = {
2042 .dmadisable_shift = -ENODEV,
2043 .midle_shift = -ENODEV,
2044 .sidle_shift = 0,
2045 .clkact_shift = -ENODEV,
2046 .enwkup_shift = -ENODEV,
2047 .srst_shift = -ENODEV,
2048 .emufree_shift = -ENODEV,
2049 .autoidle_shift = -ENODEV,
2050};
2051
2052static const struct sysc_capabilities sysc_omap4_mcasp = {
2053 .type = TI_SYSC_OMAP4_MCASP,
2054 .regbits = &sysc_regbits_omap4_mcasp,
Tony Lindgren2c63a832018-11-15 14:46:53 -08002055 .mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED,
2056};
2057
2058/*
2059 * McASP found on dra7 and later
2060 */
2061static const struct sysc_capabilities sysc_dra7_mcasp = {
2062 .type = TI_SYSC_OMAP4_SIMPLE,
2063 .regbits = &sysc_regbits_omap4_simple,
2064 .mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED,
Tony Lindgren70a65242017-12-15 09:41:09 -08002065};
2066
2067/*
2068 * FS USB host found on omap4 and later
2069 */
2070static const struct sysc_regbits sysc_regbits_omap4_usb_host_fs = {
2071 .dmadisable_shift = -ENODEV,
2072 .midle_shift = -ENODEV,
2073 .sidle_shift = 24,
2074 .clkact_shift = -ENODEV,
2075 .enwkup_shift = 26,
2076 .srst_shift = -ENODEV,
2077 .emufree_shift = -ENODEV,
2078 .autoidle_shift = -ENODEV,
2079};
2080
2081static const struct sysc_capabilities sysc_omap4_usb_host_fs = {
2082 .type = TI_SYSC_OMAP4_USB_HOST_FS,
2083 .sysc_mask = SYSC_OMAP2_ENAWAKEUP,
2084 .regbits = &sysc_regbits_omap4_usb_host_fs,
2085};
2086
Faiz Abbas7f35e632018-07-09 22:18:38 +05302087static const struct sysc_regbits sysc_regbits_dra7_mcan = {
2088 .dmadisable_shift = -ENODEV,
2089 .midle_shift = -ENODEV,
2090 .sidle_shift = -ENODEV,
2091 .clkact_shift = -ENODEV,
2092 .enwkup_shift = 4,
2093 .srst_shift = 0,
2094 .emufree_shift = -ENODEV,
2095 .autoidle_shift = -ENODEV,
2096};
2097
2098static const struct sysc_capabilities sysc_dra7_mcan = {
2099 .type = TI_SYSC_DRA7_MCAN,
2100 .sysc_mask = SYSC_DRA7_MCAN_ENAWAKEUP | SYSC_OMAP4_SOFTRESET,
2101 .regbits = &sysc_regbits_dra7_mcan,
2102};
2103
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08002104static int sysc_init_pdata(struct sysc *ddata)
2105{
2106 struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
Tony Lindgrena3e92e72019-03-21 11:00:21 -07002107 struct ti_sysc_module_data *mdata;
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08002108
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07002109 if (!pdata)
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08002110 return 0;
2111
Tony Lindgrena3e92e72019-03-21 11:00:21 -07002112 mdata = devm_kzalloc(ddata->dev, sizeof(*mdata), GFP_KERNEL);
2113 if (!mdata)
2114 return -ENOMEM;
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08002115
Tony Lindgren2b2f7de2019-05-27 04:51:53 -07002116 if (ddata->legacy_mode) {
2117 mdata->name = ddata->legacy_mode;
2118 mdata->module_pa = ddata->module_pa;
2119 mdata->module_size = ddata->module_size;
2120 mdata->offsets = ddata->offsets;
2121 mdata->nr_offsets = SYSC_MAX_REGS;
2122 mdata->cap = ddata->cap;
2123 mdata->cfg = &ddata->cfg;
2124 }
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08002125
Tony Lindgrena3e92e72019-03-21 11:00:21 -07002126 ddata->mdata = mdata;
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08002127
Tony Lindgrena3e92e72019-03-21 11:00:21 -07002128 return 0;
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08002129}
2130
Tony Lindgren70a65242017-12-15 09:41:09 -08002131static int sysc_init_match(struct sysc *ddata)
2132{
2133 const struct sysc_capabilities *cap;
2134
2135 cap = of_device_get_match_data(ddata->dev);
2136 if (!cap)
2137 return -EINVAL;
2138
2139 ddata->cap = cap;
2140 if (ddata->cap)
2141 ddata->cfg.quirks |= ddata->cap->mod_quirks;
2142
2143 return 0;
2144}
2145
Tony Lindgren76f0f772018-02-23 08:28:45 -08002146static void ti_sysc_idle(struct work_struct *work)
2147{
2148 struct sysc *ddata;
2149
2150 ddata = container_of(work, struct sysc, idle_work.work);
2151
2152 if (pm_runtime_active(ddata->dev))
2153 pm_runtime_put_sync(ddata->dev);
2154}
2155
Tony Lindgrenc4bebea2018-04-16 10:24:54 -07002156static const struct of_device_id sysc_match_table[] = {
2157 { .compatible = "simple-bus", },
2158 { /* sentinel */ },
2159};
2160
Tony Lindgren0eecc632017-10-10 14:23:43 -07002161static int sysc_probe(struct platform_device *pdev)
2162{
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08002163 struct ti_sysc_platform_data *pdata = dev_get_platdata(&pdev->dev);
Tony Lindgren0eecc632017-10-10 14:23:43 -07002164 struct sysc *ddata;
2165 int error;
2166
2167 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
2168 if (!ddata)
2169 return -ENOMEM;
2170
2171 ddata->dev = &pdev->dev;
Tony Lindgren566a9b052017-12-15 09:41:19 -08002172 platform_set_drvdata(pdev, ddata);
Tony Lindgren0eecc632017-10-10 14:23:43 -07002173
Tony Lindgren70a65242017-12-15 09:41:09 -08002174 error = sysc_init_match(ddata);
2175 if (error)
2176 return error;
2177
Tony Lindgren566a9b052017-12-15 09:41:19 -08002178 error = sysc_init_dts_quirks(ddata);
2179 if (error)
2180 goto unprepare;
2181
Tony Lindgren0eecc632017-10-10 14:23:43 -07002182 error = sysc_map_and_check_registers(ddata);
2183 if (error)
2184 goto unprepare;
2185
Tony Lindgrenc5a2de92017-12-15 09:41:23 -08002186 error = sysc_init_sysc_mask(ddata);
2187 if (error)
2188 goto unprepare;
2189
2190 error = sysc_init_idlemodes(ddata);
2191 if (error)
2192 goto unprepare;
2193
2194 error = sysc_init_syss_mask(ddata);
2195 if (error)
2196 goto unprepare;
2197
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08002198 error = sysc_init_pdata(ddata);
2199 if (error)
2200 goto unprepare;
2201
Tony Lindgren42b9c5c2019-03-21 11:00:21 -07002202 sysc_init_early_quirks(ddata);
2203
2204 error = sysc_get_clocks(ddata);
2205 if (error)
2206 return error;
2207
Tony Lindgren50622362018-04-16 10:20:27 -07002208 error = sysc_init_resets(ddata);
2209 if (error)
2210 return error;
Tony Lindgren566a9b052017-12-15 09:41:19 -08002211
2212 error = sysc_init_module(ddata);
2213 if (error)
2214 goto unprepare;
2215
Tony Lindgren1a5cd7c2019-03-21 11:00:21 -07002216 pm_runtime_enable(ddata->dev);
Tony Lindgren0eecc632017-10-10 14:23:43 -07002217 error = pm_runtime_get_sync(ddata->dev);
2218 if (error < 0) {
2219 pm_runtime_put_noidle(ddata->dev);
2220 pm_runtime_disable(ddata->dev);
2221 goto unprepare;
2222 }
2223
Tony Lindgren0eecc632017-10-10 14:23:43 -07002224 sysc_show_registers(ddata);
2225
Tony Lindgren2c355ff2018-02-22 13:58:03 -08002226 ddata->dev->type = &sysc_device_type;
Tony Lindgrenc4bebea2018-04-16 10:24:54 -07002227 error = of_platform_populate(ddata->dev->of_node, sysc_match_table,
2228 pdata ? pdata->auxdata : NULL,
Tony Lindgrenef70b0b2018-02-22 14:00:25 -08002229 ddata->dev);
Tony Lindgren0eecc632017-10-10 14:23:43 -07002230 if (error)
2231 goto err;
2232
Tony Lindgren76f0f772018-02-23 08:28:45 -08002233 INIT_DELAYED_WORK(&ddata->idle_work, ti_sysc_idle);
2234
2235 /* At least earlycon won't survive without deferred idle */
2236 if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE_ON_INIT |
2237 SYSC_QUIRK_NO_RESET_ON_INIT)) {
2238 schedule_delayed_work(&ddata->idle_work, 3000);
2239 } else {
2240 pm_runtime_put(&pdev->dev);
2241 }
Tony Lindgren0eecc632017-10-10 14:23:43 -07002242
Tony Lindgren50622362018-04-16 10:20:27 -07002243 if (!of_get_available_child_count(ddata->dev->of_node))
2244 reset_control_assert(ddata->rsts);
2245
Tony Lindgren0eecc632017-10-10 14:23:43 -07002246 return 0;
2247
2248err:
Tony Lindgren0eecc632017-10-10 14:23:43 -07002249 pm_runtime_put_sync(&pdev->dev);
2250 pm_runtime_disable(&pdev->dev);
2251unprepare:
2252 sysc_unprepare(ddata);
2253
2254 return error;
2255}
2256
Tony Lindgren684be5a2017-10-13 10:48:40 -07002257static int sysc_remove(struct platform_device *pdev)
2258{
2259 struct sysc *ddata = platform_get_drvdata(pdev);
2260 int error;
2261
Tony Lindgren76f0f772018-02-23 08:28:45 -08002262 cancel_delayed_work_sync(&ddata->idle_work);
2263
Tony Lindgren684be5a2017-10-13 10:48:40 -07002264 error = pm_runtime_get_sync(ddata->dev);
2265 if (error < 0) {
2266 pm_runtime_put_noidle(ddata->dev);
2267 pm_runtime_disable(ddata->dev);
2268 goto unprepare;
2269 }
2270
2271 of_platform_depopulate(&pdev->dev);
2272
Tony Lindgren684be5a2017-10-13 10:48:40 -07002273 pm_runtime_put_sync(&pdev->dev);
2274 pm_runtime_disable(&pdev->dev);
Tony Lindgren50622362018-04-16 10:20:27 -07002275 reset_control_assert(ddata->rsts);
Tony Lindgren684be5a2017-10-13 10:48:40 -07002276
2277unprepare:
2278 sysc_unprepare(ddata);
2279
2280 return 0;
2281}
2282
Tony Lindgren0eecc632017-10-10 14:23:43 -07002283static const struct of_device_id sysc_match[] = {
Tony Lindgren70a65242017-12-15 09:41:09 -08002284 { .compatible = "ti,sysc-omap2", .data = &sysc_omap2, },
2285 { .compatible = "ti,sysc-omap2-timer", .data = &sysc_omap2_timer, },
2286 { .compatible = "ti,sysc-omap4", .data = &sysc_omap4, },
2287 { .compatible = "ti,sysc-omap4-timer", .data = &sysc_omap4_timer, },
2288 { .compatible = "ti,sysc-omap4-simple", .data = &sysc_omap4_simple, },
2289 { .compatible = "ti,sysc-omap3430-sr", .data = &sysc_34xx_sr, },
2290 { .compatible = "ti,sysc-omap3630-sr", .data = &sysc_36xx_sr, },
2291 { .compatible = "ti,sysc-omap4-sr", .data = &sysc_omap4_sr, },
2292 { .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, },
2293 { .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, },
2294 { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, },
Tony Lindgren2c63a832018-11-15 14:46:53 -08002295 { .compatible = "ti,sysc-dra7-mcasp", .data = &sysc_dra7_mcasp, },
Tony Lindgren70a65242017-12-15 09:41:09 -08002296 { .compatible = "ti,sysc-usb-host-fs",
2297 .data = &sysc_omap4_usb_host_fs, },
Faiz Abbas7f35e632018-07-09 22:18:38 +05302298 { .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, },
Tony Lindgren0eecc632017-10-10 14:23:43 -07002299 { },
2300};
2301MODULE_DEVICE_TABLE(of, sysc_match);
2302
2303static struct platform_driver sysc_driver = {
2304 .probe = sysc_probe,
Tony Lindgren684be5a2017-10-13 10:48:40 -07002305 .remove = sysc_remove,
Tony Lindgren0eecc632017-10-10 14:23:43 -07002306 .driver = {
2307 .name = "ti-sysc",
2308 .of_match_table = sysc_match,
2309 .pm = &sysc_pm_ops,
2310 },
2311};
Tony Lindgren2c355ff2018-02-22 13:58:03 -08002312
2313static int __init sysc_init(void)
2314{
2315 bus_register_notifier(&platform_bus_type, &sysc_nb);
2316
2317 return platform_driver_register(&sysc_driver);
2318}
2319module_init(sysc_init);
2320
2321static void __exit sysc_exit(void)
2322{
2323 bus_unregister_notifier(&platform_bus_type, &sysc_nb);
2324 platform_driver_unregister(&sysc_driver);
2325}
2326module_exit(sysc_exit);
Tony Lindgren0eecc632017-10-10 14:23:43 -07002327
2328MODULE_DESCRIPTION("TI sysc interconnect target driver");
2329MODULE_LICENSE("GPL v2");