blob: 7d82d5add7c1db2eaabc78e0f9fb7e030e31db61 [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 Lindgren0eecc632017-10-10 14:23:43 -070017#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <linux/pm_runtime.h>
20#include <linux/of_address.h>
21#include <linux/of_platform.h>
Tony Lindgren2c355ff2018-02-22 13:58:03 -080022#include <linux/slab.h>
23
Tony Lindgren70a65242017-12-15 09:41:09 -080024#include <linux/platform_data/ti-sysc.h>
25
26#include <dt-bindings/bus/ti-sysc.h>
Tony Lindgren0eecc632017-10-10 14:23:43 -070027
28enum sysc_registers {
29 SYSC_REVISION,
30 SYSC_SYSCONFIG,
31 SYSC_SYSSTATUS,
32 SYSC_MAX_REGS,
33};
34
35static const char * const reg_names[] = { "rev", "sysc", "syss", };
36
37enum sysc_clocks {
38 SYSC_FCK,
39 SYSC_ICK,
40 SYSC_MAX_CLOCKS,
41};
42
43static const char * const clock_names[] = { "fck", "ick", };
44
Tony Lindgrenc5a2de92017-12-15 09:41:23 -080045#define SYSC_IDLEMODE_MASK 3
46#define SYSC_CLOCKACTIVITY_MASK 3
47
Tony Lindgren0eecc632017-10-10 14:23:43 -070048/**
49 * struct sysc - TI sysc interconnect target module registers and capabilities
50 * @dev: struct device pointer
51 * @module_pa: physical address of the interconnect target module
52 * @module_size: size of the interconnect target module
53 * @module_va: virtual address of the interconnect target module
54 * @offsets: register offsets from module base
55 * @clocks: clocks used by the interconnect target module
56 * @legacy_mode: configured for legacy mode if set
Tony Lindgren70a65242017-12-15 09:41:09 -080057 * @cap: interconnect target module capabilities
58 * @cfg: interconnect target module configuration
Tony Lindgren566a9b052017-12-15 09:41:19 -080059 * @name: name if available
60 * @revision: interconnect target module revision
Tony Lindgren62020f22018-02-22 13:59:44 -080061 * @needs_resume: runtime resume needed on resume from suspend
Tony Lindgren0eecc632017-10-10 14:23:43 -070062 */
63struct sysc {
64 struct device *dev;
65 u64 module_pa;
66 u32 module_size;
67 void __iomem *module_va;
68 int offsets[SYSC_MAX_REGS];
69 struct clk *clocks[SYSC_MAX_CLOCKS];
70 const char *legacy_mode;
Tony Lindgren70a65242017-12-15 09:41:09 -080071 const struct sysc_capabilities *cap;
72 struct sysc_config cfg;
Tony Lindgren566a9b052017-12-15 09:41:19 -080073 const char *name;
74 u32 revision;
Tony Lindgren62020f22018-02-22 13:59:44 -080075 bool enabled;
76 bool needs_resume;
Tony Lindgren0eecc632017-10-10 14:23:43 -070077};
78
Tony Lindgren566a9b052017-12-15 09:41:19 -080079static u32 sysc_read(struct sysc *ddata, int offset)
80{
81 if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) {
82 u32 val;
83
84 val = readw_relaxed(ddata->module_va + offset);
85 val |= (readw_relaxed(ddata->module_va + offset + 4) << 16);
86
87 return val;
88 }
89
90 return readl_relaxed(ddata->module_va + offset);
91}
92
Tony Lindgren0eecc632017-10-10 14:23:43 -070093static u32 sysc_read_revision(struct sysc *ddata)
94{
Tony Lindgren566a9b052017-12-15 09:41:19 -080095 int offset = ddata->offsets[SYSC_REVISION];
96
97 if (offset < 0)
98 return 0;
99
100 return sysc_read(ddata, offset);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700101}
102
103static int sysc_get_one_clock(struct sysc *ddata,
104 enum sysc_clocks index)
105{
106 const char *name;
107 int error;
108
109 switch (index) {
110 case SYSC_FCK:
111 break;
112 case SYSC_ICK:
113 break;
114 default:
115 return -EINVAL;
116 }
117 name = clock_names[index];
118
119 ddata->clocks[index] = devm_clk_get(ddata->dev, name);
120 if (IS_ERR(ddata->clocks[index])) {
121 if (PTR_ERR(ddata->clocks[index]) == -ENOENT)
122 return 0;
123
124 dev_err(ddata->dev, "clock get error for %s: %li\n",
125 name, PTR_ERR(ddata->clocks[index]));
126
127 return PTR_ERR(ddata->clocks[index]);
128 }
129
130 error = clk_prepare(ddata->clocks[index]);
131 if (error) {
132 dev_err(ddata->dev, "clock prepare error for %s: %i\n",
133 name, error);
134
135 return error;
136 }
137
138 return 0;
139}
140
141static int sysc_get_clocks(struct sysc *ddata)
142{
143 int i, error;
144
Tony Lindgren0eecc632017-10-10 14:23:43 -0700145 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
146 error = sysc_get_one_clock(ddata, i);
147 if (error && error != -ENOENT)
148 return error;
149 }
150
151 return 0;
152}
153
154/**
155 * sysc_parse_and_check_child_range - parses module IO region from ranges
156 * @ddata: device driver data
157 *
158 * In general we only need rev, syss, and sysc registers and not the whole
159 * module range. But we do want the offsets for these registers from the
160 * module base. This allows us to check them against the legacy hwmod
161 * platform data. Let's also check the ranges are configured properly.
162 */
163static int sysc_parse_and_check_child_range(struct sysc *ddata)
164{
165 struct device_node *np = ddata->dev->of_node;
166 const __be32 *ranges;
167 u32 nr_addr, nr_size;
168 int len, error;
169
170 ranges = of_get_property(np, "ranges", &len);
171 if (!ranges) {
172 dev_err(ddata->dev, "missing ranges for %pOF\n", np);
173
174 return -ENOENT;
175 }
176
177 len /= sizeof(*ranges);
178
179 if (len < 3) {
180 dev_err(ddata->dev, "incomplete ranges for %pOF\n", np);
181
182 return -EINVAL;
183 }
184
185 error = of_property_read_u32(np, "#address-cells", &nr_addr);
186 if (error)
187 return -ENOENT;
188
189 error = of_property_read_u32(np, "#size-cells", &nr_size);
190 if (error)
191 return -ENOENT;
192
193 if (nr_addr != 1 || nr_size != 1) {
194 dev_err(ddata->dev, "invalid ranges for %pOF\n", np);
195
196 return -EINVAL;
197 }
198
199 ranges++;
200 ddata->module_pa = of_translate_address(np, ranges++);
201 ddata->module_size = be32_to_cpup(ranges);
202
203 dev_dbg(ddata->dev, "interconnect target 0x%llx size 0x%x for %pOF\n",
204 ddata->module_pa, ddata->module_size, np);
205
206 return 0;
207}
208
Tony Lindgren3bb37c82018-02-22 14:05:14 -0800209static struct device_node *stdout_path;
210
211static void sysc_init_stdout_path(struct sysc *ddata)
212{
213 struct device_node *np = NULL;
214 const char *uart;
215
216 if (IS_ERR(stdout_path))
217 return;
218
219 if (stdout_path)
220 return;
221
222 np = of_find_node_by_path("/chosen");
223 if (!np)
224 goto err;
225
226 uart = of_get_property(np, "stdout-path", NULL);
227 if (!uart)
228 goto err;
229
230 np = of_find_node_by_path(uart);
231 if (!np)
232 goto err;
233
234 stdout_path = np;
235
236 return;
237
238err:
239 stdout_path = ERR_PTR(-ENODEV);
240}
241
242static void sysc_check_quirk_stdout(struct sysc *ddata,
243 struct device_node *np)
244{
245 sysc_init_stdout_path(ddata);
246 if (np != stdout_path)
247 return;
248
249 ddata->cfg.quirks |= SYSC_QUIRK_NO_IDLE_ON_INIT |
250 SYSC_QUIRK_NO_RESET_ON_INIT;
251}
252
Tony Lindgren0eecc632017-10-10 14:23:43 -0700253/**
254 * sysc_check_one_child - check child configuration
255 * @ddata: device driver data
256 * @np: child device node
257 *
258 * Let's avoid messy situations where we have new interconnect target
259 * node but children have "ti,hwmods". These belong to the interconnect
260 * target node and are managed by this driver.
261 */
262static int sysc_check_one_child(struct sysc *ddata,
263 struct device_node *np)
264{
265 const char *name;
266
267 name = of_get_property(np, "ti,hwmods", NULL);
268 if (name)
269 dev_warn(ddata->dev, "really a child ti,hwmods property?");
270
Tony Lindgren3bb37c82018-02-22 14:05:14 -0800271 sysc_check_quirk_stdout(ddata, np);
272
Tony Lindgren0eecc632017-10-10 14:23:43 -0700273 return 0;
274}
275
276static int sysc_check_children(struct sysc *ddata)
277{
278 struct device_node *child;
279 int error;
280
281 for_each_child_of_node(ddata->dev->of_node, child) {
282 error = sysc_check_one_child(ddata, child);
283 if (error)
284 return error;
285 }
286
287 return 0;
288}
289
Tony Lindgrena7199e22017-12-15 09:41:14 -0800290/*
291 * So far only I2C uses 16-bit read access with clockactivity with revision
292 * in two registers with stride of 4. We can detect this based on the rev
293 * register size to configure things far enough to be able to properly read
294 * the revision register.
295 */
296static void sysc_check_quirk_16bit(struct sysc *ddata, struct resource *res)
297{
298 if (resource_size(res) == 8) {
299 dev_dbg(ddata->dev,
300 "enabling 16-bit and clockactivity quirks\n");
301 ddata->cfg.quirks |= SYSC_QUIRK_16BIT | SYSC_QUIRK_USE_CLOCKACT;
302 }
303}
304
Tony Lindgren0eecc632017-10-10 14:23:43 -0700305/**
306 * sysc_parse_one - parses the interconnect target module registers
307 * @ddata: device driver data
308 * @reg: register to parse
309 */
310static int sysc_parse_one(struct sysc *ddata, enum sysc_registers reg)
311{
312 struct resource *res;
313 const char *name;
314
315 switch (reg) {
316 case SYSC_REVISION:
317 case SYSC_SYSCONFIG:
318 case SYSC_SYSSTATUS:
319 name = reg_names[reg];
320 break;
321 default:
322 return -EINVAL;
323 }
324
325 res = platform_get_resource_byname(to_platform_device(ddata->dev),
326 IORESOURCE_MEM, name);
327 if (!res) {
328 dev_dbg(ddata->dev, "has no %s register\n", name);
329 ddata->offsets[reg] = -ENODEV;
330
331 return 0;
332 }
333
334 ddata->offsets[reg] = res->start - ddata->module_pa;
Tony Lindgrena7199e22017-12-15 09:41:14 -0800335 if (reg == SYSC_REVISION)
336 sysc_check_quirk_16bit(ddata, res);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700337
338 return 0;
339}
340
341static int sysc_parse_registers(struct sysc *ddata)
342{
343 int i, error;
344
345 for (i = 0; i < SYSC_MAX_REGS; i++) {
346 error = sysc_parse_one(ddata, i);
347 if (error)
348 return error;
349 }
350
351 return 0;
352}
353
354/**
355 * sysc_check_registers - check for misconfigured register overlaps
356 * @ddata: device driver data
357 */
358static int sysc_check_registers(struct sysc *ddata)
359{
360 int i, j, nr_regs = 0, nr_matches = 0;
361
362 for (i = 0; i < SYSC_MAX_REGS; i++) {
363 if (ddata->offsets[i] < 0)
364 continue;
365
366 if (ddata->offsets[i] > (ddata->module_size - 4)) {
367 dev_err(ddata->dev, "register outside module range");
368
369 return -EINVAL;
370 }
371
372 for (j = 0; j < SYSC_MAX_REGS; j++) {
373 if (ddata->offsets[j] < 0)
374 continue;
375
376 if (ddata->offsets[i] == ddata->offsets[j])
377 nr_matches++;
378 }
379 nr_regs++;
380 }
381
382 if (nr_regs < 1) {
383 dev_err(ddata->dev, "missing registers\n");
384
385 return -EINVAL;
386 }
387
388 if (nr_matches > nr_regs) {
389 dev_err(ddata->dev, "overlapping registers: (%i/%i)",
390 nr_regs, nr_matches);
391
392 return -EINVAL;
393 }
394
395 return 0;
396}
397
398/**
399 * syc_ioremap - ioremap register space for the interconnect target module
400 * @ddata: deviec driver data
401 *
402 * Note that the interconnect target module registers can be anywhere
403 * within the first child device address space. For example, SGX has
404 * them at offset 0x1fc00 in the 32MB module address space. We just
405 * what we need around the interconnect target module registers.
406 */
407static int sysc_ioremap(struct sysc *ddata)
408{
409 u32 size = 0;
410
411 if (ddata->offsets[SYSC_SYSSTATUS] >= 0)
412 size = ddata->offsets[SYSC_SYSSTATUS];
413 else if (ddata->offsets[SYSC_SYSCONFIG] >= 0)
414 size = ddata->offsets[SYSC_SYSCONFIG];
415 else if (ddata->offsets[SYSC_REVISION] >= 0)
416 size = ddata->offsets[SYSC_REVISION];
417 else
418 return -EINVAL;
419
420 size &= 0xfff00;
421 size += SZ_256;
422
423 ddata->module_va = devm_ioremap(ddata->dev,
424 ddata->module_pa,
425 size);
426 if (!ddata->module_va)
427 return -EIO;
428
429 return 0;
430}
431
432/**
433 * sysc_map_and_check_registers - ioremap and check device registers
434 * @ddata: device driver data
435 */
436static int sysc_map_and_check_registers(struct sysc *ddata)
437{
438 int error;
439
440 error = sysc_parse_and_check_child_range(ddata);
441 if (error)
442 return error;
443
444 error = sysc_check_children(ddata);
445 if (error)
446 return error;
447
448 error = sysc_parse_registers(ddata);
449 if (error)
450 return error;
451
452 error = sysc_ioremap(ddata);
453 if (error)
454 return error;
455
456 error = sysc_check_registers(ddata);
457 if (error)
458 return error;
459
460 return 0;
461}
462
463/**
464 * sysc_show_rev - read and show interconnect target module revision
465 * @bufp: buffer to print the information to
466 * @ddata: device driver data
467 */
468static int sysc_show_rev(char *bufp, struct sysc *ddata)
469{
Tony Lindgren566a9b052017-12-15 09:41:19 -0800470 int len;
Tony Lindgren0eecc632017-10-10 14:23:43 -0700471
472 if (ddata->offsets[SYSC_REVISION] < 0)
473 return sprintf(bufp, ":NA");
474
Tony Lindgren566a9b052017-12-15 09:41:19 -0800475 len = sprintf(bufp, ":%08x", ddata->revision);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700476
477 return len;
478}
479
480static int sysc_show_reg(struct sysc *ddata,
481 char *bufp, enum sysc_registers reg)
482{
483 if (ddata->offsets[reg] < 0)
484 return sprintf(bufp, ":NA");
485
486 return sprintf(bufp, ":%x", ddata->offsets[reg]);
487}
488
489/**
490 * sysc_show_registers - show information about interconnect target module
491 * @ddata: device driver data
492 */
493static void sysc_show_registers(struct sysc *ddata)
494{
495 char buf[128];
496 char *bufp = buf;
497 int i;
498
499 for (i = 0; i < SYSC_MAX_REGS; i++)
500 bufp += sysc_show_reg(ddata, bufp, i);
501
502 bufp += sysc_show_rev(bufp, ddata);
503
504 dev_dbg(ddata->dev, "%llx:%x%s\n",
505 ddata->module_pa, ddata->module_size,
506 buf);
507}
508
Arnd Bergmanna4a5d492017-10-13 11:25:32 +0200509static int __maybe_unused sysc_runtime_suspend(struct device *dev)
Tony Lindgren0eecc632017-10-10 14:23:43 -0700510{
511 struct sysc *ddata;
512 int i;
513
514 ddata = dev_get_drvdata(dev);
515
516 if (ddata->legacy_mode)
517 return 0;
518
519 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
520 if (IS_ERR_OR_NULL(ddata->clocks[i]))
521 continue;
522 clk_disable(ddata->clocks[i]);
523 }
524
525 return 0;
526}
527
Arnd Bergmanna4a5d492017-10-13 11:25:32 +0200528static int __maybe_unused sysc_runtime_resume(struct device *dev)
Tony Lindgren0eecc632017-10-10 14:23:43 -0700529{
530 struct sysc *ddata;
531 int i, error;
532
533 ddata = dev_get_drvdata(dev);
534
535 if (ddata->legacy_mode)
536 return 0;
537
538 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
539 if (IS_ERR_OR_NULL(ddata->clocks[i]))
540 continue;
541 error = clk_enable(ddata->clocks[i]);
542 if (error)
543 return error;
544 }
545
546 return 0;
547}
548
Tony Lindgren62020f22018-02-22 13:59:44 -0800549#ifdef CONFIG_PM_SLEEP
550static int sysc_suspend(struct device *dev)
551{
552 struct sysc *ddata;
553
554 ddata = dev_get_drvdata(dev);
555
556 if (!ddata->enabled)
557 return 0;
558
559 ddata->needs_resume = true;
560
561 return sysc_runtime_suspend(dev);
562}
563
564static int sysc_resume(struct device *dev)
565{
566 struct sysc *ddata;
567
568 ddata = dev_get_drvdata(dev);
569 if (ddata->needs_resume) {
570 ddata->needs_resume = false;
571
572 return sysc_runtime_resume(dev);
573 }
574
575 return 0;
576}
577#endif
578
Tony Lindgren0eecc632017-10-10 14:23:43 -0700579static const struct dev_pm_ops sysc_pm_ops = {
Tony Lindgren62020f22018-02-22 13:59:44 -0800580 SET_SYSTEM_SLEEP_PM_OPS(sysc_suspend, sysc_resume)
Tony Lindgren0eecc632017-10-10 14:23:43 -0700581 SET_RUNTIME_PM_OPS(sysc_runtime_suspend,
582 sysc_runtime_resume,
583 NULL)
584};
585
Tony Lindgren566a9b052017-12-15 09:41:19 -0800586/* At this point the module is configured enough to read the revision */
587static int sysc_init_module(struct sysc *ddata)
588{
589 int error;
590
591 error = pm_runtime_get_sync(ddata->dev);
592 if (error < 0) {
593 pm_runtime_put_noidle(ddata->dev);
594
595 return 0;
596 }
597 ddata->revision = sysc_read_revision(ddata);
598 pm_runtime_put_sync(ddata->dev);
599
600 return 0;
601}
602
Tony Lindgrenc5a2de92017-12-15 09:41:23 -0800603static int sysc_init_sysc_mask(struct sysc *ddata)
604{
605 struct device_node *np = ddata->dev->of_node;
606 int error;
607 u32 val;
608
609 error = of_property_read_u32(np, "ti,sysc-mask", &val);
610 if (error)
611 return 0;
612
613 if (val)
614 ddata->cfg.sysc_val = val & ddata->cap->sysc_mask;
615 else
616 ddata->cfg.sysc_val = ddata->cap->sysc_mask;
617
618 return 0;
619}
620
621static int sysc_init_idlemode(struct sysc *ddata, u8 *idlemodes,
622 const char *name)
623{
624 struct device_node *np = ddata->dev->of_node;
625 struct property *prop;
626 const __be32 *p;
627 u32 val;
628
629 of_property_for_each_u32(np, name, prop, p, val) {
630 if (val >= SYSC_NR_IDLEMODES) {
631 dev_err(ddata->dev, "invalid idlemode: %i\n", val);
632 return -EINVAL;
633 }
634 *idlemodes |= (1 << val);
635 }
636
637 return 0;
638}
639
640static int sysc_init_idlemodes(struct sysc *ddata)
641{
642 int error;
643
644 error = sysc_init_idlemode(ddata, &ddata->cfg.midlemodes,
645 "ti,sysc-midle");
646 if (error)
647 return error;
648
649 error = sysc_init_idlemode(ddata, &ddata->cfg.sidlemodes,
650 "ti,sysc-sidle");
651 if (error)
652 return error;
653
654 return 0;
655}
656
657/*
658 * Only some devices on omap4 and later have SYSCONFIG reset done
659 * bit. We can detect this if there is no SYSSTATUS at all, or the
660 * SYSTATUS bit 0 is not used. Note that some SYSSTATUS registers
661 * have multiple bits for the child devices like OHCI and EHCI.
662 * Depends on SYSC being parsed first.
663 */
664static int sysc_init_syss_mask(struct sysc *ddata)
665{
666 struct device_node *np = ddata->dev->of_node;
667 int error;
668 u32 val;
669
670 error = of_property_read_u32(np, "ti,syss-mask", &val);
671 if (error) {
672 if ((ddata->cap->type == TI_SYSC_OMAP4 ||
673 ddata->cap->type == TI_SYSC_OMAP4_TIMER) &&
674 (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET))
675 ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS;
676
677 return 0;
678 }
679
680 if (!(val & 1) && (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET))
681 ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS;
682
683 ddata->cfg.syss_mask = val;
684
685 return 0;
686}
687
Tony Lindgren2c355ff2018-02-22 13:58:03 -0800688/*
689 * Many child device drivers need to have fck available to get the clock
690 * rate for device internal configuration.
691 */
692static int sysc_child_add_fck(struct sysc *ddata,
693 struct device *child)
694{
695 struct clk *fck;
696 struct clk_lookup *l;
697 const char *name = clock_names[SYSC_FCK];
698
699 if (IS_ERR_OR_NULL(ddata->clocks[SYSC_FCK]))
700 return 0;
701
702 fck = clk_get(child, name);
703 if (!IS_ERR(fck)) {
704 clk_put(fck);
705
706 return -EEXIST;
707 }
708
709 l = clkdev_create(ddata->clocks[SYSC_FCK], name, dev_name(child));
710
711 return l ? 0 : -ENODEV;
712}
713
714static struct device_type sysc_device_type = {
715};
716
717static struct sysc *sysc_child_to_parent(struct device *dev)
718{
719 struct device *parent = dev->parent;
720
721 if (!parent || parent->type != &sysc_device_type)
722 return NULL;
723
724 return dev_get_drvdata(parent);
725}
726
727static int sysc_notifier_call(struct notifier_block *nb,
728 unsigned long event, void *device)
729{
730 struct device *dev = device;
731 struct sysc *ddata;
732 int error;
733
734 ddata = sysc_child_to_parent(dev);
735 if (!ddata)
736 return NOTIFY_DONE;
737
738 switch (event) {
739 case BUS_NOTIFY_ADD_DEVICE:
740 error = sysc_child_add_fck(ddata, dev);
741 if (error && error != -EEXIST)
742 dev_warn(ddata->dev, "could not add %s fck: %i\n",
743 dev_name(dev), error);
744 break;
745 default:
746 break;
747 }
748
749 return NOTIFY_DONE;
750}
751
752static struct notifier_block sysc_nb = {
753 .notifier_call = sysc_notifier_call,
754};
755
Tony Lindgren566a9b052017-12-15 09:41:19 -0800756/* Device tree configured quirks */
757struct sysc_dts_quirk {
758 const char *name;
759 u32 mask;
760};
761
762static const struct sysc_dts_quirk sysc_dts_quirks[] = {
763 { .name = "ti,no-idle-on-init",
764 .mask = SYSC_QUIRK_NO_IDLE_ON_INIT, },
765 { .name = "ti,no-reset-on-init",
766 .mask = SYSC_QUIRK_NO_RESET_ON_INIT, },
767};
768
769static int sysc_init_dts_quirks(struct sysc *ddata)
770{
771 struct device_node *np = ddata->dev->of_node;
772 const struct property *prop;
773 int i, len, error;
774 u32 val;
775
776 ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);
777
778 for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) {
779 prop = of_get_property(np, sysc_dts_quirks[i].name, &len);
780 if (!prop)
781 break;
782
783 ddata->cfg.quirks |= sysc_dts_quirks[i].mask;
784 }
785
786 error = of_property_read_u32(np, "ti,sysc-delay-us", &val);
787 if (!error) {
788 if (val > 255) {
789 dev_warn(ddata->dev, "bad ti,sysc-delay-us: %i\n",
790 val);
791 }
792
793 ddata->cfg.srst_udelay = (u8)val;
794 }
795
796 return 0;
797}
798
Tony Lindgren0eecc632017-10-10 14:23:43 -0700799static void sysc_unprepare(struct sysc *ddata)
800{
801 int i;
802
803 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
804 if (!IS_ERR_OR_NULL(ddata->clocks[i]))
805 clk_unprepare(ddata->clocks[i]);
806 }
807}
808
Tony Lindgren70a65242017-12-15 09:41:09 -0800809/*
810 * Common sysc register bits found on omap2, also known as type1
811 */
812static const struct sysc_regbits sysc_regbits_omap2 = {
813 .dmadisable_shift = -ENODEV,
814 .midle_shift = 12,
815 .sidle_shift = 3,
816 .clkact_shift = 8,
817 .emufree_shift = 5,
818 .enwkup_shift = 2,
819 .srst_shift = 1,
820 .autoidle_shift = 0,
821};
822
823static const struct sysc_capabilities sysc_omap2 = {
824 .type = TI_SYSC_OMAP2,
825 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY | SYSC_OMAP2_EMUFREE |
826 SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_SOFTRESET |
827 SYSC_OMAP2_AUTOIDLE,
828 .regbits = &sysc_regbits_omap2,
829};
830
831/* All omap2 and 3 timers, and timers 1, 2 & 10 on omap 4 and 5 */
832static const struct sysc_capabilities sysc_omap2_timer = {
833 .type = TI_SYSC_OMAP2_TIMER,
834 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY | SYSC_OMAP2_EMUFREE |
835 SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_SOFTRESET |
836 SYSC_OMAP2_AUTOIDLE,
837 .regbits = &sysc_regbits_omap2,
838 .mod_quirks = SYSC_QUIRK_USE_CLOCKACT,
839};
840
841/*
842 * SHAM2 (SHA1/MD5) sysc found on omap3, a variant of sysc_regbits_omap2
843 * with different sidle position
844 */
845static const struct sysc_regbits sysc_regbits_omap3_sham = {
846 .dmadisable_shift = -ENODEV,
847 .midle_shift = -ENODEV,
848 .sidle_shift = 4,
849 .clkact_shift = -ENODEV,
850 .enwkup_shift = -ENODEV,
851 .srst_shift = 1,
852 .autoidle_shift = 0,
853 .emufree_shift = -ENODEV,
854};
855
856static const struct sysc_capabilities sysc_omap3_sham = {
857 .type = TI_SYSC_OMAP3_SHAM,
858 .sysc_mask = SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE,
859 .regbits = &sysc_regbits_omap3_sham,
860};
861
862/*
863 * AES register bits found on omap3 and later, a variant of
864 * sysc_regbits_omap2 with different sidle position
865 */
866static const struct sysc_regbits sysc_regbits_omap3_aes = {
867 .dmadisable_shift = -ENODEV,
868 .midle_shift = -ENODEV,
869 .sidle_shift = 6,
870 .clkact_shift = -ENODEV,
871 .enwkup_shift = -ENODEV,
872 .srst_shift = 1,
873 .autoidle_shift = 0,
874 .emufree_shift = -ENODEV,
875};
876
877static const struct sysc_capabilities sysc_omap3_aes = {
878 .type = TI_SYSC_OMAP3_AES,
879 .sysc_mask = SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE,
880 .regbits = &sysc_regbits_omap3_aes,
881};
882
883/*
884 * Common sysc register bits found on omap4, also known as type2
885 */
886static const struct sysc_regbits sysc_regbits_omap4 = {
887 .dmadisable_shift = 16,
888 .midle_shift = 4,
889 .sidle_shift = 2,
890 .clkact_shift = -ENODEV,
891 .enwkup_shift = -ENODEV,
892 .emufree_shift = 1,
893 .srst_shift = 0,
894 .autoidle_shift = -ENODEV,
895};
896
897static const struct sysc_capabilities sysc_omap4 = {
898 .type = TI_SYSC_OMAP4,
899 .sysc_mask = SYSC_OMAP4_DMADISABLE | SYSC_OMAP4_FREEEMU |
900 SYSC_OMAP4_SOFTRESET,
901 .regbits = &sysc_regbits_omap4,
902};
903
904static const struct sysc_capabilities sysc_omap4_timer = {
905 .type = TI_SYSC_OMAP4_TIMER,
906 .sysc_mask = SYSC_OMAP4_DMADISABLE | SYSC_OMAP4_FREEEMU |
907 SYSC_OMAP4_SOFTRESET,
908 .regbits = &sysc_regbits_omap4,
909};
910
911/*
912 * Common sysc register bits found on omap4, also known as type3
913 */
914static const struct sysc_regbits sysc_regbits_omap4_simple = {
915 .dmadisable_shift = -ENODEV,
916 .midle_shift = 2,
917 .sidle_shift = 0,
918 .clkact_shift = -ENODEV,
919 .enwkup_shift = -ENODEV,
920 .srst_shift = -ENODEV,
921 .emufree_shift = -ENODEV,
922 .autoidle_shift = -ENODEV,
923};
924
925static const struct sysc_capabilities sysc_omap4_simple = {
926 .type = TI_SYSC_OMAP4_SIMPLE,
927 .regbits = &sysc_regbits_omap4_simple,
928};
929
930/*
931 * SmartReflex sysc found on omap34xx
932 */
933static const struct sysc_regbits sysc_regbits_omap34xx_sr = {
934 .dmadisable_shift = -ENODEV,
935 .midle_shift = -ENODEV,
936 .sidle_shift = -ENODEV,
937 .clkact_shift = 20,
938 .enwkup_shift = -ENODEV,
939 .srst_shift = -ENODEV,
940 .emufree_shift = -ENODEV,
941 .autoidle_shift = -ENODEV,
942};
943
944static const struct sysc_capabilities sysc_34xx_sr = {
945 .type = TI_SYSC_OMAP34XX_SR,
946 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY,
947 .regbits = &sysc_regbits_omap34xx_sr,
948 .mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED,
949};
950
951/*
952 * SmartReflex sysc found on omap36xx and later
953 */
954static const struct sysc_regbits sysc_regbits_omap36xx_sr = {
955 .dmadisable_shift = -ENODEV,
956 .midle_shift = -ENODEV,
957 .sidle_shift = 24,
958 .clkact_shift = -ENODEV,
959 .enwkup_shift = 26,
960 .srst_shift = -ENODEV,
961 .emufree_shift = -ENODEV,
962 .autoidle_shift = -ENODEV,
963};
964
965static const struct sysc_capabilities sysc_36xx_sr = {
966 .type = TI_SYSC_OMAP36XX_SR,
Tony Lindgren3267c082018-01-22 09:32:53 -0800967 .sysc_mask = SYSC_OMAP3_SR_ENAWAKEUP,
Tony Lindgren70a65242017-12-15 09:41:09 -0800968 .regbits = &sysc_regbits_omap36xx_sr,
969 .mod_quirks = SYSC_QUIRK_UNCACHED,
970};
971
972static const struct sysc_capabilities sysc_omap4_sr = {
973 .type = TI_SYSC_OMAP4_SR,
974 .regbits = &sysc_regbits_omap36xx_sr,
975};
976
977/*
978 * McASP register bits found on omap4 and later
979 */
980static const struct sysc_regbits sysc_regbits_omap4_mcasp = {
981 .dmadisable_shift = -ENODEV,
982 .midle_shift = -ENODEV,
983 .sidle_shift = 0,
984 .clkact_shift = -ENODEV,
985 .enwkup_shift = -ENODEV,
986 .srst_shift = -ENODEV,
987 .emufree_shift = -ENODEV,
988 .autoidle_shift = -ENODEV,
989};
990
991static const struct sysc_capabilities sysc_omap4_mcasp = {
992 .type = TI_SYSC_OMAP4_MCASP,
993 .regbits = &sysc_regbits_omap4_mcasp,
994};
995
996/*
997 * FS USB host found on omap4 and later
998 */
999static const struct sysc_regbits sysc_regbits_omap4_usb_host_fs = {
1000 .dmadisable_shift = -ENODEV,
1001 .midle_shift = -ENODEV,
1002 .sidle_shift = 24,
1003 .clkact_shift = -ENODEV,
1004 .enwkup_shift = 26,
1005 .srst_shift = -ENODEV,
1006 .emufree_shift = -ENODEV,
1007 .autoidle_shift = -ENODEV,
1008};
1009
1010static const struct sysc_capabilities sysc_omap4_usb_host_fs = {
1011 .type = TI_SYSC_OMAP4_USB_HOST_FS,
1012 .sysc_mask = SYSC_OMAP2_ENAWAKEUP,
1013 .regbits = &sysc_regbits_omap4_usb_host_fs,
1014};
1015
1016static int sysc_init_match(struct sysc *ddata)
1017{
1018 const struct sysc_capabilities *cap;
1019
1020 cap = of_device_get_match_data(ddata->dev);
1021 if (!cap)
1022 return -EINVAL;
1023
1024 ddata->cap = cap;
1025 if (ddata->cap)
1026 ddata->cfg.quirks |= ddata->cap->mod_quirks;
1027
1028 return 0;
1029}
1030
Tony Lindgren0eecc632017-10-10 14:23:43 -07001031static int sysc_probe(struct platform_device *pdev)
1032{
Tony Lindgren0eecc632017-10-10 14:23:43 -07001033 struct sysc *ddata;
1034 int error;
1035
1036 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
1037 if (!ddata)
1038 return -ENOMEM;
1039
1040 ddata->dev = &pdev->dev;
Tony Lindgren566a9b052017-12-15 09:41:19 -08001041 platform_set_drvdata(pdev, ddata);
Tony Lindgren0eecc632017-10-10 14:23:43 -07001042
Tony Lindgren70a65242017-12-15 09:41:09 -08001043 error = sysc_init_match(ddata);
1044 if (error)
1045 return error;
1046
Tony Lindgren566a9b052017-12-15 09:41:19 -08001047 error = sysc_init_dts_quirks(ddata);
1048 if (error)
1049 goto unprepare;
1050
Tony Lindgren0eecc632017-10-10 14:23:43 -07001051 error = sysc_get_clocks(ddata);
1052 if (error)
1053 return error;
1054
1055 error = sysc_map_and_check_registers(ddata);
1056 if (error)
1057 goto unprepare;
1058
Tony Lindgrenc5a2de92017-12-15 09:41:23 -08001059 error = sysc_init_sysc_mask(ddata);
1060 if (error)
1061 goto unprepare;
1062
1063 error = sysc_init_idlemodes(ddata);
1064 if (error)
1065 goto unprepare;
1066
1067 error = sysc_init_syss_mask(ddata);
1068 if (error)
1069 goto unprepare;
1070
Tony Lindgren0eecc632017-10-10 14:23:43 -07001071 pm_runtime_enable(ddata->dev);
Tony Lindgren566a9b052017-12-15 09:41:19 -08001072
1073 error = sysc_init_module(ddata);
1074 if (error)
1075 goto unprepare;
1076
Tony Lindgren0eecc632017-10-10 14:23:43 -07001077 error = pm_runtime_get_sync(ddata->dev);
1078 if (error < 0) {
1079 pm_runtime_put_noidle(ddata->dev);
1080 pm_runtime_disable(ddata->dev);
1081 goto unprepare;
1082 }
1083
1084 pm_runtime_use_autosuspend(ddata->dev);
1085
1086 sysc_show_registers(ddata);
1087
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001088 ddata->dev->type = &sysc_device_type;
Tony Lindgren0eecc632017-10-10 14:23:43 -07001089 error = of_platform_populate(ddata->dev->of_node,
1090 NULL, NULL, ddata->dev);
1091 if (error)
1092 goto err;
1093
1094 pm_runtime_mark_last_busy(ddata->dev);
1095 pm_runtime_put_autosuspend(ddata->dev);
1096
1097 return 0;
1098
1099err:
1100 pm_runtime_dont_use_autosuspend(&pdev->dev);
1101 pm_runtime_put_sync(&pdev->dev);
1102 pm_runtime_disable(&pdev->dev);
1103unprepare:
1104 sysc_unprepare(ddata);
1105
1106 return error;
1107}
1108
Tony Lindgren684be5a2017-10-13 10:48:40 -07001109static int sysc_remove(struct platform_device *pdev)
1110{
1111 struct sysc *ddata = platform_get_drvdata(pdev);
1112 int error;
1113
1114 error = pm_runtime_get_sync(ddata->dev);
1115 if (error < 0) {
1116 pm_runtime_put_noidle(ddata->dev);
1117 pm_runtime_disable(ddata->dev);
1118 goto unprepare;
1119 }
1120
1121 of_platform_depopulate(&pdev->dev);
1122
1123 pm_runtime_dont_use_autosuspend(&pdev->dev);
1124 pm_runtime_put_sync(&pdev->dev);
1125 pm_runtime_disable(&pdev->dev);
1126
1127unprepare:
1128 sysc_unprepare(ddata);
1129
1130 return 0;
1131}
1132
Tony Lindgren0eecc632017-10-10 14:23:43 -07001133static const struct of_device_id sysc_match[] = {
Tony Lindgren70a65242017-12-15 09:41:09 -08001134 { .compatible = "ti,sysc-omap2", .data = &sysc_omap2, },
1135 { .compatible = "ti,sysc-omap2-timer", .data = &sysc_omap2_timer, },
1136 { .compatible = "ti,sysc-omap4", .data = &sysc_omap4, },
1137 { .compatible = "ti,sysc-omap4-timer", .data = &sysc_omap4_timer, },
1138 { .compatible = "ti,sysc-omap4-simple", .data = &sysc_omap4_simple, },
1139 { .compatible = "ti,sysc-omap3430-sr", .data = &sysc_34xx_sr, },
1140 { .compatible = "ti,sysc-omap3630-sr", .data = &sysc_36xx_sr, },
1141 { .compatible = "ti,sysc-omap4-sr", .data = &sysc_omap4_sr, },
1142 { .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, },
1143 { .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, },
1144 { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, },
1145 { .compatible = "ti,sysc-usb-host-fs",
1146 .data = &sysc_omap4_usb_host_fs, },
Tony Lindgren0eecc632017-10-10 14:23:43 -07001147 { },
1148};
1149MODULE_DEVICE_TABLE(of, sysc_match);
1150
1151static struct platform_driver sysc_driver = {
1152 .probe = sysc_probe,
Tony Lindgren684be5a2017-10-13 10:48:40 -07001153 .remove = sysc_remove,
Tony Lindgren0eecc632017-10-10 14:23:43 -07001154 .driver = {
1155 .name = "ti-sysc",
1156 .of_match_table = sysc_match,
1157 .pm = &sysc_pm_ops,
1158 },
1159};
Tony Lindgren2c355ff2018-02-22 13:58:03 -08001160
1161static int __init sysc_init(void)
1162{
1163 bus_register_notifier(&platform_bus_type, &sysc_nb);
1164
1165 return platform_driver_register(&sysc_driver);
1166}
1167module_init(sysc_init);
1168
1169static void __exit sysc_exit(void)
1170{
1171 bus_unregister_notifier(&platform_bus_type, &sysc_nb);
1172 platform_driver_unregister(&sysc_driver);
1173}
1174module_exit(sysc_exit);
Tony Lindgren0eecc632017-10-10 14:23:43 -07001175
1176MODULE_DESCRIPTION("TI sysc interconnect target driver");
1177MODULE_LICENSE("GPL v2");