diff options
author | Tony Lindgren <tony@atomide.com> | 2017-12-15 12:41:19 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2017-12-21 10:28:54 -0500 |
commit | 566a9b05e1fa47dcfb93a4459145d0fdc06d3046 (patch) | |
tree | 6b7d9d55fd4872ce316462906d5c10a6286d2ccb | |
parent | a7199e2b91ded41adbb6fd384a85e358d25f48c8 (diff) |
bus: ti-sysc: Handle module quirks based dts configuration
Let's configure few module quirks via device tree using the
properties for "ti,no-idle-on-init", "ti,no-reset-on-init"
and "ti,sysc-delay-us".
Let's also reorder the probe a bit so we have pdata available
earlier, and move the PM runtime calls to sysc_init_module()
from sysc_read_revision().
Signed-off-by: Tony Lindgren <tony@atomide.com>
-rw-r--r-- | drivers/bus/ti-sysc.c | 114 | ||||
-rw-r--r-- | include/linux/platform_data/ti-sysc.h | 6 |
2 files changed, 102 insertions, 18 deletions
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 4c1e59e53a0c..090612460cef 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c | |||
@@ -50,6 +50,8 @@ static const char * const clock_names[] = { "fck", "ick", }; | |||
50 | * @legacy_mode: configured for legacy mode if set | 50 | * @legacy_mode: configured for legacy mode if set |
51 | * @cap: interconnect target module capabilities | 51 | * @cap: interconnect target module capabilities |
52 | * @cfg: interconnect target module configuration | 52 | * @cfg: interconnect target module configuration |
53 | * @name: name if available | ||
54 | * @revision: interconnect target module revision | ||
53 | */ | 55 | */ |
54 | struct sysc { | 56 | struct sysc { |
55 | struct device *dev; | 57 | struct device *dev; |
@@ -61,12 +63,32 @@ struct sysc { | |||
61 | const char *legacy_mode; | 63 | const char *legacy_mode; |
62 | const struct sysc_capabilities *cap; | 64 | const struct sysc_capabilities *cap; |
63 | struct sysc_config cfg; | 65 | struct sysc_config cfg; |
66 | const char *name; | ||
67 | u32 revision; | ||
64 | }; | 68 | }; |
65 | 69 | ||
70 | static u32 sysc_read(struct sysc *ddata, int offset) | ||
71 | { | ||
72 | if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) { | ||
73 | u32 val; | ||
74 | |||
75 | val = readw_relaxed(ddata->module_va + offset); | ||
76 | val |= (readw_relaxed(ddata->module_va + offset + 4) << 16); | ||
77 | |||
78 | return val; | ||
79 | } | ||
80 | |||
81 | return readl_relaxed(ddata->module_va + offset); | ||
82 | } | ||
83 | |||
66 | static u32 sysc_read_revision(struct sysc *ddata) | 84 | static u32 sysc_read_revision(struct sysc *ddata) |
67 | { | 85 | { |
68 | return readl_relaxed(ddata->module_va + | 86 | int offset = ddata->offsets[SYSC_REVISION]; |
69 | ddata->offsets[SYSC_REVISION]); | 87 | |
88 | if (offset < 0) | ||
89 | return 0; | ||
90 | |||
91 | return sysc_read(ddata, offset); | ||
70 | } | 92 | } |
71 | 93 | ||
72 | static int sysc_get_one_clock(struct sysc *ddata, | 94 | static int sysc_get_one_clock(struct sysc *ddata, |
@@ -393,22 +415,12 @@ static int sysc_map_and_check_registers(struct sysc *ddata) | |||
393 | */ | 415 | */ |
394 | static int sysc_show_rev(char *bufp, struct sysc *ddata) | 416 | static int sysc_show_rev(char *bufp, struct sysc *ddata) |
395 | { | 417 | { |
396 | int error, len; | 418 | int len; |
397 | 419 | ||
398 | if (ddata->offsets[SYSC_REVISION] < 0) | 420 | if (ddata->offsets[SYSC_REVISION] < 0) |
399 | return sprintf(bufp, ":NA"); | 421 | return sprintf(bufp, ":NA"); |
400 | 422 | ||
401 | error = pm_runtime_get_sync(ddata->dev); | 423 | len = sprintf(bufp, ":%08x", ddata->revision); |
402 | if (error < 0) { | ||
403 | pm_runtime_put_noidle(ddata->dev); | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | len = sprintf(bufp, ":%08x", sysc_read_revision(ddata)); | ||
409 | |||
410 | pm_runtime_mark_last_busy(ddata->dev); | ||
411 | pm_runtime_put_autosuspend(ddata->dev); | ||
412 | 424 | ||
413 | return len; | 425 | return len; |
414 | } | 426 | } |
@@ -488,6 +500,66 @@ static const struct dev_pm_ops sysc_pm_ops = { | |||
488 | NULL) | 500 | NULL) |
489 | }; | 501 | }; |
490 | 502 | ||
503 | /* At this point the module is configured enough to read the revision */ | ||
504 | static int sysc_init_module(struct sysc *ddata) | ||
505 | { | ||
506 | int error; | ||
507 | |||
508 | error = pm_runtime_get_sync(ddata->dev); | ||
509 | if (error < 0) { | ||
510 | pm_runtime_put_noidle(ddata->dev); | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | ddata->revision = sysc_read_revision(ddata); | ||
515 | pm_runtime_put_sync(ddata->dev); | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | /* Device tree configured quirks */ | ||
521 | struct sysc_dts_quirk { | ||
522 | const char *name; | ||
523 | u32 mask; | ||
524 | }; | ||
525 | |||
526 | static const struct sysc_dts_quirk sysc_dts_quirks[] = { | ||
527 | { .name = "ti,no-idle-on-init", | ||
528 | .mask = SYSC_QUIRK_NO_IDLE_ON_INIT, }, | ||
529 | { .name = "ti,no-reset-on-init", | ||
530 | .mask = SYSC_QUIRK_NO_RESET_ON_INIT, }, | ||
531 | }; | ||
532 | |||
533 | static int sysc_init_dts_quirks(struct sysc *ddata) | ||
534 | { | ||
535 | struct device_node *np = ddata->dev->of_node; | ||
536 | const struct property *prop; | ||
537 | int i, len, error; | ||
538 | u32 val; | ||
539 | |||
540 | ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL); | ||
541 | |||
542 | for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { | ||
543 | prop = of_get_property(np, sysc_dts_quirks[i].name, &len); | ||
544 | if (!prop) | ||
545 | break; | ||
546 | |||
547 | ddata->cfg.quirks |= sysc_dts_quirks[i].mask; | ||
548 | } | ||
549 | |||
550 | error = of_property_read_u32(np, "ti,sysc-delay-us", &val); | ||
551 | if (!error) { | ||
552 | if (val > 255) { | ||
553 | dev_warn(ddata->dev, "bad ti,sysc-delay-us: %i\n", | ||
554 | val); | ||
555 | } | ||
556 | |||
557 | ddata->cfg.srst_udelay = (u8)val; | ||
558 | } | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
491 | static void sysc_unprepare(struct sysc *ddata) | 563 | static void sysc_unprepare(struct sysc *ddata) |
492 | { | 564 | { |
493 | int i; | 565 | int i; |
@@ -722,7 +794,6 @@ static int sysc_init_match(struct sysc *ddata) | |||
722 | 794 | ||
723 | static int sysc_probe(struct platform_device *pdev) | 795 | static int sysc_probe(struct platform_device *pdev) |
724 | { | 796 | { |
725 | struct device_node *np = pdev->dev.of_node; | ||
726 | struct sysc *ddata; | 797 | struct sysc *ddata; |
727 | int error; | 798 | int error; |
728 | 799 | ||
@@ -731,12 +802,16 @@ static int sysc_probe(struct platform_device *pdev) | |||
731 | return -ENOMEM; | 802 | return -ENOMEM; |
732 | 803 | ||
733 | ddata->dev = &pdev->dev; | 804 | ddata->dev = &pdev->dev; |
734 | ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL); | 805 | platform_set_drvdata(pdev, ddata); |
735 | 806 | ||
736 | error = sysc_init_match(ddata); | 807 | error = sysc_init_match(ddata); |
737 | if (error) | 808 | if (error) |
738 | return error; | 809 | return error; |
739 | 810 | ||
811 | error = sysc_init_dts_quirks(ddata); | ||
812 | if (error) | ||
813 | goto unprepare; | ||
814 | |||
740 | error = sysc_get_clocks(ddata); | 815 | error = sysc_get_clocks(ddata); |
741 | if (error) | 816 | if (error) |
742 | return error; | 817 | return error; |
@@ -745,9 +820,12 @@ static int sysc_probe(struct platform_device *pdev) | |||
745 | if (error) | 820 | if (error) |
746 | goto unprepare; | 821 | goto unprepare; |
747 | 822 | ||
748 | platform_set_drvdata(pdev, ddata); | ||
749 | |||
750 | pm_runtime_enable(ddata->dev); | 823 | pm_runtime_enable(ddata->dev); |
824 | |||
825 | error = sysc_init_module(ddata); | ||
826 | if (error) | ||
827 | goto unprepare; | ||
828 | |||
751 | error = pm_runtime_get_sync(ddata->dev); | 829 | error = pm_runtime_get_sync(ddata->dev); |
752 | if (error < 0) { | 830 | if (error < 0) { |
753 | pm_runtime_put_noidle(ddata->dev); | 831 | pm_runtime_put_noidle(ddata->dev); |
diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h index 059be6f6fa94..28e5a61d4abc 100644 --- a/include/linux/platform_data/ti-sysc.h +++ b/include/linux/platform_data/ti-sysc.h | |||
@@ -41,6 +41,10 @@ struct sysc_regbits { | |||
41 | s8 emufree_shift; | 41 | s8 emufree_shift; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | #define SYSC_QUIRK_NO_IDLE_ON_INIT BIT(6) | ||
45 | #define SYSC_QUIRK_NO_RESET_ON_INIT BIT(5) | ||
46 | #define SYSC_QUIRK_OPT_CLKS_NEEDED BIT(4) | ||
47 | #define SYSC_QUIRK_OPT_CLKS_IN_RESET BIT(3) | ||
44 | #define SYSC_QUIRK_16BIT BIT(2) | 48 | #define SYSC_QUIRK_16BIT BIT(2) |
45 | #define SYSC_QUIRK_UNCACHED BIT(1) | 49 | #define SYSC_QUIRK_UNCACHED BIT(1) |
46 | #define SYSC_QUIRK_USE_CLOCKACT BIT(0) | 50 | #define SYSC_QUIRK_USE_CLOCKACT BIT(0) |
@@ -61,9 +65,11 @@ struct sysc_capabilities { | |||
61 | 65 | ||
62 | /** | 66 | /** |
63 | * struct sysc_config - configuration for an interconnect target module | 67 | * struct sysc_config - configuration for an interconnect target module |
68 | * @srst_udelay: optional delay needed after OCP soft reset | ||
64 | * @quirks: bitmask of enabled quirks | 69 | * @quirks: bitmask of enabled quirks |
65 | */ | 70 | */ |
66 | struct sysc_config { | 71 | struct sysc_config { |
72 | u8 srst_udelay; | ||
67 | u32 quirks; | 73 | u32 quirks; |
68 | }; | 74 | }; |
69 | 75 | ||