summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/bus/ti-sysc.c226
-rw-r--r--include/linux/platform_data/ti-sysc.h1
2 files changed, 224 insertions, 3 deletions
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index 50fcb04e8179..5aeab4533b5f 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -14,8 +14,10 @@
14#include <linux/io.h> 14#include <linux/io.h>
15#include <linux/clk.h> 15#include <linux/clk.h>
16#include <linux/clkdev.h> 16#include <linux/clkdev.h>
17#include <linux/delay.h>
17#include <linux/module.h> 18#include <linux/module.h>
18#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20#include <linux/pm_domain.h>
19#include <linux/pm_runtime.h> 21#include <linux/pm_runtime.h>
20#include <linux/of_address.h> 22#include <linux/of_address.h>
21#include <linux/of_platform.h> 23#include <linux/of_platform.h>
@@ -68,6 +70,7 @@ struct sysc {
68 u32 revision; 70 u32 revision;
69 bool enabled; 71 bool enabled;
70 bool needs_resume; 72 bool needs_resume;
73 bool child_needs_resume;
71 struct delayed_work idle_work; 74 struct delayed_work idle_work;
72}; 75};
73 76
@@ -474,6 +477,14 @@ static int sysc_show_reg(struct sysc *ddata,
474 return sprintf(bufp, ":%x", ddata->offsets[reg]); 477 return sprintf(bufp, ":%x", ddata->offsets[reg]);
475} 478}
476 479
480static int sysc_show_name(char *bufp, struct sysc *ddata)
481{
482 if (!ddata->name)
483 return 0;
484
485 return sprintf(bufp, ":%s", ddata->name);
486}
487
477/** 488/**
478 * sysc_show_registers - show information about interconnect target module 489 * sysc_show_registers - show information about interconnect target module
479 * @ddata: device driver data 490 * @ddata: device driver data
@@ -488,7 +499,7 @@ static void sysc_show_registers(struct sysc *ddata)
488 bufp += sysc_show_reg(ddata, bufp, i); 499 bufp += sysc_show_reg(ddata, bufp, i);
489 500
490 bufp += sysc_show_rev(bufp, ddata); 501 bufp += sysc_show_rev(bufp, ddata);
491 bufp += sysc_show_rev(bufp, ddata); 502 bufp += sysc_show_name(bufp, ddata);
492 503
493 dev_dbg(ddata->dev, "%llx:%x%s\n", 504 dev_dbg(ddata->dev, "%llx:%x%s\n",
494 ddata->module_pa, ddata->module_size, 505 ddata->module_pa, ddata->module_size,
@@ -612,11 +623,93 @@ static const struct dev_pm_ops sysc_pm_ops = {
612 NULL) 623 NULL)
613}; 624};
614 625
626/* Module revision register based quirks */
627struct sysc_revision_quirk {
628 const char *name;
629 u32 base;
630 int rev_offset;
631 int sysc_offset;
632 int syss_offset;
633 u32 revision;
634 u32 revision_mask;
635 u32 quirks;
636};
637
638#define SYSC_QUIRK(optname, optbase, optrev, optsysc, optsyss, \
639 optrev_val, optrevmask, optquirkmask) \
640 { \
641 .name = (optname), \
642 .base = (optbase), \
643 .rev_offset = (optrev), \
644 .sysc_offset = (optsysc), \
645 .syss_offset = (optsyss), \
646 .revision = (optrev_val), \
647 .revision_mask = (optrevmask), \
648 .quirks = (optquirkmask), \
649 }
650
651static const struct sysc_revision_quirk sysc_revision_quirks[] = {
652 /* These drivers need to be fixed to not use pm_runtime_irq_safe() */
653 SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffffffff,
654 SYSC_QUIRK_LEGACY_IDLE),
655 SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000020, 0xffffffff,
656 SYSC_QUIRK_LEGACY_IDLE),
657 SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000030, 0xffffffff,
658 SYSC_QUIRK_LEGACY_IDLE),
659 SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff,
660 SYSC_QUIRK_LEGACY_IDLE),
661 SYSC_QUIRK("smartreflex", 0, -1, 0x24, -1, 0x00000000, 0xffffffff,
662 SYSC_QUIRK_LEGACY_IDLE),
663 SYSC_QUIRK("smartreflex", 0, -1, 0x38, -1, 0x00000000, 0xffffffff,
664 SYSC_QUIRK_LEGACY_IDLE),
665 SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff,
666 SYSC_QUIRK_LEGACY_IDLE),
667 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
668 SYSC_QUIRK_LEGACY_IDLE),
669};
670
671static void sysc_init_revision_quirks(struct sysc *ddata)
672{
673 const struct sysc_revision_quirk *q;
674 int i;
675
676 for (i = 0; i < ARRAY_SIZE(sysc_revision_quirks); i++) {
677 q = &sysc_revision_quirks[i];
678
679 if (q->base && q->base != ddata->module_pa)
680 continue;
681
682 if (q->rev_offset >= 0 &&
683 q->rev_offset != ddata->offsets[SYSC_REVISION])
684 continue;
685
686 if (q->sysc_offset >= 0 &&
687 q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
688 continue;
689
690 if (q->syss_offset >= 0 &&
691 q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
692 continue;
693
694 if (q->revision == ddata->revision ||
695 (q->revision & q->revision_mask) ==
696 (ddata->revision & q->revision_mask)) {
697 ddata->name = q->name;
698 ddata->cfg.quirks |= q->quirks;
699 }
700 }
701}
702
615/* At this point the module is configured enough to read the revision */ 703/* At this point the module is configured enough to read the revision */
616static int sysc_init_module(struct sysc *ddata) 704static int sysc_init_module(struct sysc *ddata)
617{ 705{
618 int error; 706 int error;
619 707
708 if (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE_ON_INIT) {
709 ddata->revision = sysc_read_revision(ddata);
710 goto rev_quirks;
711 }
712
620 error = pm_runtime_get_sync(ddata->dev); 713 error = pm_runtime_get_sync(ddata->dev);
621 if (error < 0) { 714 if (error < 0) {
622 pm_runtime_put_noidle(ddata->dev); 715 pm_runtime_put_noidle(ddata->dev);
@@ -626,6 +719,9 @@ static int sysc_init_module(struct sysc *ddata)
626 ddata->revision = sysc_read_revision(ddata); 719 ddata->revision = sysc_read_revision(ddata);
627 pm_runtime_put_sync(ddata->dev); 720 pm_runtime_put_sync(ddata->dev);
628 721
722rev_quirks:
723 sysc_init_revision_quirks(ddata);
724
629 return 0; 725 return 0;
630} 726}
631 727
@@ -753,6 +849,127 @@ static struct sysc *sysc_child_to_parent(struct device *dev)
753 return dev_get_drvdata(parent); 849 return dev_get_drvdata(parent);
754} 850}
755 851
852static int __maybe_unused sysc_child_runtime_suspend(struct device *dev)
853{
854 struct sysc *ddata;
855 int error;
856
857 ddata = sysc_child_to_parent(dev);
858
859 error = pm_generic_runtime_suspend(dev);
860 if (error)
861 return error;
862
863 if (!ddata->enabled)
864 return 0;
865
866 return sysc_runtime_suspend(ddata->dev);
867}
868
869static int __maybe_unused sysc_child_runtime_resume(struct device *dev)
870{
871 struct sysc *ddata;
872 int error;
873
874 ddata = sysc_child_to_parent(dev);
875
876 if (!ddata->enabled) {
877 error = sysc_runtime_resume(ddata->dev);
878 if (error < 0)
879 dev_err(ddata->dev,
880 "%s error: %i\n", __func__, error);
881 }
882
883 return pm_generic_runtime_resume(dev);
884}
885
886#ifdef CONFIG_PM_SLEEP
887static int sysc_child_suspend_noirq(struct device *dev)
888{
889 struct sysc *ddata;
890 int error;
891
892 ddata = sysc_child_to_parent(dev);
893
894 error = pm_generic_suspend_noirq(dev);
895 if (error)
896 return error;
897
898 if (!pm_runtime_status_suspended(dev)) {
899 error = pm_generic_runtime_suspend(dev);
900 if (error)
901 return error;
902
903 error = sysc_runtime_suspend(ddata->dev);
904 if (error)
905 return error;
906
907 ddata->child_needs_resume = true;
908 }
909
910 return 0;
911}
912
913static int sysc_child_resume_noirq(struct device *dev)
914{
915 struct sysc *ddata;
916 int error;
917
918 ddata = sysc_child_to_parent(dev);
919
920 if (ddata->child_needs_resume) {
921 ddata->child_needs_resume = false;
922
923 error = sysc_runtime_resume(ddata->dev);
924 if (error)
925 dev_err(ddata->dev,
926 "%s runtime resume error: %i\n",
927 __func__, error);
928
929 error = pm_generic_runtime_resume(dev);
930 if (error)
931 dev_err(ddata->dev,
932 "%s generic runtime resume: %i\n",
933 __func__, error);
934 }
935
936 return pm_generic_resume_noirq(dev);
937}
938#endif
939
940struct dev_pm_domain sysc_child_pm_domain = {
941 .ops = {
942 SET_RUNTIME_PM_OPS(sysc_child_runtime_suspend,
943 sysc_child_runtime_resume,
944 NULL)
945 USE_PLATFORM_PM_SLEEP_OPS
946 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_child_suspend_noirq,
947 sysc_child_resume_noirq)
948 }
949};
950
951/**
952 * sysc_legacy_idle_quirk - handle children in omap_device compatible way
953 * @ddata: device driver data
954 * @child: child device driver
955 *
956 * Allow idle for child devices as done with _od_runtime_suspend().
957 * Otherwise many child devices will not idle because of the permanent
958 * parent usecount set in pm_runtime_irq_safe().
959 *
960 * Note that the long term solution is to just modify the child device
961 * drivers to not set pm_runtime_irq_safe() and then this can be just
962 * dropped.
963 */
964static void sysc_legacy_idle_quirk(struct sysc *ddata, struct device *child)
965{
966 if (!ddata->legacy_mode)
967 return;
968
969 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
970 dev_pm_domain_set(child, &sysc_child_pm_domain);
971}
972
756static int sysc_notifier_call(struct notifier_block *nb, 973static int sysc_notifier_call(struct notifier_block *nb,
757 unsigned long event, void *device) 974 unsigned long event, void *device)
758{ 975{
@@ -770,6 +987,7 @@ static int sysc_notifier_call(struct notifier_block *nb,
770 if (error && error != -EEXIST) 987 if (error && error != -EEXIST)
771 dev_warn(ddata->dev, "could not add %s fck: %i\n", 988 dev_warn(ddata->dev, "could not add %s fck: %i\n",
772 dev_name(dev), error); 989 dev_name(dev), error);
990 sysc_legacy_idle_quirk(ddata, dev);
773 break; 991 break;
774 default: 992 default:
775 break; 993 break;
@@ -974,7 +1192,8 @@ static const struct sysc_capabilities sysc_34xx_sr = {
974 .type = TI_SYSC_OMAP34XX_SR, 1192 .type = TI_SYSC_OMAP34XX_SR,
975 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY, 1193 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY,
976 .regbits = &sysc_regbits_omap34xx_sr, 1194 .regbits = &sysc_regbits_omap34xx_sr,
977 .mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED, 1195 .mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED |
1196 SYSC_QUIRK_LEGACY_IDLE,
978}; 1197};
979 1198
980/* 1199/*
@@ -995,12 +1214,13 @@ static const struct sysc_capabilities sysc_36xx_sr = {
995 .type = TI_SYSC_OMAP36XX_SR, 1214 .type = TI_SYSC_OMAP36XX_SR,
996 .sysc_mask = SYSC_OMAP3_SR_ENAWAKEUP, 1215 .sysc_mask = SYSC_OMAP3_SR_ENAWAKEUP,
997 .regbits = &sysc_regbits_omap36xx_sr, 1216 .regbits = &sysc_regbits_omap36xx_sr,
998 .mod_quirks = SYSC_QUIRK_UNCACHED, 1217 .mod_quirks = SYSC_QUIRK_UNCACHED | SYSC_QUIRK_LEGACY_IDLE,
999}; 1218};
1000 1219
1001static const struct sysc_capabilities sysc_omap4_sr = { 1220static const struct sysc_capabilities sysc_omap4_sr = {
1002 .type = TI_SYSC_OMAP4_SR, 1221 .type = TI_SYSC_OMAP4_SR,
1003 .regbits = &sysc_regbits_omap36xx_sr, 1222 .regbits = &sysc_regbits_omap36xx_sr,
1223 .mod_quirks = SYSC_QUIRK_LEGACY_IDLE,
1004}; 1224};
1005 1225
1006/* 1226/*
diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
index 4176cb90e195..80ce28d40832 100644
--- a/include/linux/platform_data/ti-sysc.h
+++ b/include/linux/platform_data/ti-sysc.h
@@ -45,6 +45,7 @@ struct sysc_regbits {
45 s8 emufree_shift; 45 s8 emufree_shift;
46}; 46};
47 47
48#define SYSC_QUIRK_LEGACY_IDLE BIT(8)
48#define SYSC_QUIRK_RESET_STATUS BIT(7) 49#define SYSC_QUIRK_RESET_STATUS BIT(7)
49#define SYSC_QUIRK_NO_IDLE_ON_INIT BIT(6) 50#define SYSC_QUIRK_NO_IDLE_ON_INIT BIT(6)
50#define SYSC_QUIRK_NO_RESET_ON_INIT BIT(5) 51#define SYSC_QUIRK_NO_RESET_ON_INIT BIT(5)