aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2018-09-24 15:16:54 -0400
committerTony Lindgren <tony@atomide.com>2018-09-24 15:16:54 -0400
commit40d9f9124822013331367fb4ab59936c3ac944d6 (patch)
treef4173f2fd0469a011d0beb4bfdad376c03aa95c8
parent5b394b2ddf0347bef56e50c69a58773c94343ff3 (diff)
bus: ti-sysc: Defer suspend as needed
We don't care when we suspend but some our children do. In order to avoid tagging various modules with SYSC_QUIRK_RESOURCE_PROVIDER, let's do it automatically by tagging modules that are busy on suspend for noirq suspend. This way we can just do module detection on define DEBUG. Note that we still need to keep SYSC_QUIRK_LEGACY_IDLE flag around so the our legacy single-child devices that set pm_runtime_irq_safe() can manage the interconnect target module themselves. Signed-off-by: Tony Lindgren <tony@atomide.com>
-rw-r--r--drivers/bus/ti-sysc.c118
-rw-r--r--include/linux/platform_data/ti-sysc.h1
2 files changed, 61 insertions, 58 deletions
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index c9bac9dc4637..087a67617eef 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -87,6 +87,7 @@ struct sysc {
87 u32 revision; 87 u32 revision;
88 bool enabled; 88 bool enabled;
89 bool needs_resume; 89 bool needs_resume;
90 unsigned int noirq_suspend:1;
90 bool child_needs_resume; 91 bool child_needs_resume;
91 struct delayed_work idle_work; 92 struct delayed_work idle_work;
92}; 93};
@@ -712,19 +713,25 @@ static int sysc_suspend(struct device *dev)
712 713
713 ddata = dev_get_drvdata(dev); 714 ddata = dev_get_drvdata(dev);
714 715
715 if (ddata->cfg.quirks & (SYSC_QUIRK_RESOURCE_PROVIDER | 716 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
716 SYSC_QUIRK_LEGACY_IDLE))
717 return 0; 717 return 0;
718 718
719 if (!ddata->enabled) 719 if (!ddata->enabled || ddata->noirq_suspend)
720 return 0; 720 return 0;
721 721
722 dev_dbg(ddata->dev, "%s %s\n", __func__, 722 dev_dbg(ddata->dev, "%s %s\n", __func__,
723 ddata->name ? ddata->name : ""); 723 ddata->name ? ddata->name : "");
724 724
725 error = pm_runtime_put_sync_suspend(dev); 725 error = pm_runtime_put_sync_suspend(dev);
726 if (error < 0) { 726 if (error == -EBUSY) {
727 dev_warn(ddata->dev, "%s not idle %i %s\n", 727 dev_dbg(ddata->dev, "%s busy, tagging for noirq suspend %s\n",
728 __func__, ddata->name ? ddata->name : "");
729
730 ddata->noirq_suspend = true;
731
732 return 0;
733 } else if (error < 0) {
734 dev_warn(ddata->dev, "%s cannot suspend %i %s\n",
728 __func__, error, 735 __func__, error,
729 ddata->name ? ddata->name : ""); 736 ddata->name ? ddata->name : "");
730 737
@@ -743,73 +750,86 @@ static int sysc_resume(struct device *dev)
743 750
744 ddata = dev_get_drvdata(dev); 751 ddata = dev_get_drvdata(dev);
745 752
746 if (ddata->cfg.quirks & (SYSC_QUIRK_RESOURCE_PROVIDER | 753 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
747 SYSC_QUIRK_LEGACY_IDLE))
748 return 0; 754 return 0;
749 755
750 if (ddata->needs_resume) { 756 if (!ddata->needs_resume || ddata->noirq_suspend)
751 dev_dbg(ddata->dev, "%s %s\n", __func__, 757 return 0;
752 ddata->name ? ddata->name : "");
753 758
754 error = pm_runtime_get_sync(dev); 759 dev_dbg(ddata->dev, "%s %s\n", __func__,
755 if (error < 0) { 760 ddata->name ? ddata->name : "");
756 dev_err(ddata->dev, "%s error %i %s\n",
757 __func__, error,
758 ddata->name ? ddata->name : "");
759 761
760 return error; 762 error = pm_runtime_get_sync(dev);
761 } 763 if (error < 0) {
764 dev_err(ddata->dev, "%s error %i %s\n",
765 __func__, error,
766 ddata->name ? ddata->name : "");
762 767
763 ddata->needs_resume = false; 768 return error;
764 } 769 }
765 770
771 ddata->needs_resume = false;
772
766 return 0; 773 return 0;
767} 774}
768 775
769static int sysc_noirq_suspend(struct device *dev) 776static int sysc_noirq_suspend(struct device *dev)
770{ 777{
771 struct sysc *ddata; 778 struct sysc *ddata;
779 int error;
772 780
773 ddata = dev_get_drvdata(dev); 781 ddata = dev_get_drvdata(dev);
774 782
775 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE) 783 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
776 return 0; 784 return 0;
777 785
778 if (!(ddata->cfg.quirks & SYSC_QUIRK_RESOURCE_PROVIDER)) 786 if (!ddata->enabled || !ddata->noirq_suspend)
779 return 0;
780
781 if (!ddata->enabled)
782 return 0; 787 return 0;
783 788
784 dev_dbg(ddata->dev, "%s %s\n", __func__, 789 dev_dbg(ddata->dev, "%s %s\n", __func__,
785 ddata->name ? ddata->name : ""); 790 ddata->name ? ddata->name : "");
786 791
792 error = sysc_runtime_suspend(dev);
793 if (error) {
794 dev_warn(ddata->dev, "%s busy %i %s\n",
795 __func__, error, ddata->name ? ddata->name : "");
796
797 return 0;
798 }
799
787 ddata->needs_resume = true; 800 ddata->needs_resume = true;
788 801
789 return sysc_runtime_suspend(dev); 802 return 0;
790} 803}
791 804
792static int sysc_noirq_resume(struct device *dev) 805static int sysc_noirq_resume(struct device *dev)
793{ 806{
794 struct sysc *ddata; 807 struct sysc *ddata;
808 int error;
795 809
796 ddata = dev_get_drvdata(dev); 810 ddata = dev_get_drvdata(dev);
797 811
798 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE) 812 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
799 return 0; 813 return 0;
800 814
801 if (!(ddata->cfg.quirks & SYSC_QUIRK_RESOURCE_PROVIDER)) 815 if (!ddata->needs_resume || !ddata->noirq_suspend)
802 return 0; 816 return 0;
803 817
804 if (ddata->needs_resume) { 818 dev_dbg(ddata->dev, "%s %s\n", __func__,
805 dev_dbg(ddata->dev, "%s %s\n", __func__, 819 ddata->name ? ddata->name : "");
806 ddata->name ? ddata->name : "");
807 820
808 ddata->needs_resume = false; 821 error = sysc_runtime_resume(dev);
822 if (error) {
823 dev_warn(ddata->dev, "%s cannot resume %i %s\n",
824 __func__, error,
825 ddata->name ? ddata->name : "");
809 826
810 return sysc_runtime_resume(dev); 827 return error;
811 } 828 }
812 829
830 /* Maybe also reconsider clearing noirq_suspend at some point */
831 ddata->needs_resume = false;
832
813 return 0; 833 return 0;
814} 834}
815#endif 835#endif
@@ -848,26 +868,6 @@ struct sysc_revision_quirk {
848 } 868 }
849 869
850static const struct sysc_revision_quirk sysc_revision_quirks[] = { 870static const struct sysc_revision_quirk sysc_revision_quirks[] = {
851 /* These need to use noirq_suspend */
852 SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff,
853 SYSC_QUIRK_RESOURCE_PROVIDER),
854 SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xffffffff,
855 SYSC_QUIRK_RESOURCE_PROVIDER),
856 SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffffffff,
857 SYSC_QUIRK_RESOURCE_PROVIDER),
858 SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff,
859 SYSC_QUIRK_RESOURCE_PROVIDER),
860 SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xffffffff,
861 SYSC_QUIRK_RESOURCE_PROVIDER),
862 SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff,
863 SYSC_QUIRK_RESOURCE_PROVIDER),
864 SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff,
865 SYSC_QUIRK_RESOURCE_PROVIDER),
866 SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff,
867 SYSC_QUIRK_RESOURCE_PROVIDER),
868 SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff,
869 SYSC_QUIRK_RESOURCE_PROVIDER),
870
871 /* These drivers need to be fixed to not use pm_runtime_irq_safe() */ 871 /* These drivers need to be fixed to not use pm_runtime_irq_safe() */
872 SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffffffff, 872 SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffffffff,
873 SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET), 873 SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET),
@@ -892,23 +892,25 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
892 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffffffff, 892 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffffffff,
893 SYSC_QUIRK_LEGACY_IDLE), 893 SYSC_QUIRK_LEGACY_IDLE),
894 894
895 /* These devices don't yet suspend properly without legacy setting */
896 SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffffffff,
897 SYSC_QUIRK_LEGACY_IDLE),
898 SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xffffffff,
899 SYSC_QUIRK_LEGACY_IDLE),
900 SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0d00, 0xffffffff,
901 SYSC_QUIRK_LEGACY_IDLE),
902
903#ifdef DEBUG 895#ifdef DEBUG
904 SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff, 0), 896 SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff, 0),
897 SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
905 SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0), 898 SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0),
906 SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 0), 899 SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 0),
907 SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0), 900 SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
908 SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0), 901 SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0),
902 SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xffffffff, 0),
909 SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0), 903 SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0),
910 SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0), 904 SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0),
905 SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffffffff, 0),
911 SYSC_QUIRK("mailbox", 0, 0, 0x10, -1, 0x00000400, 0xffffffff, 0), 906 SYSC_QUIRK("mailbox", 0, 0, 0x10, -1, 0x00000400, 0xffffffff, 0),
907 SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xffffffff, 0),
908 SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0),
909 SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0),
910 SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
911 SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff, 0),
912 SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffffffff, 0),
913 SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0),
912 SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40000902, 0xffffffff, 0), 914 SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40000902, 0xffffffff, 0),
913 SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40002903, 0xffffffff, 0), 915 SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40002903, 0xffffffff, 0),
914 SYSC_QUIRK("spinlock", 0, 0, 0x10, -1, 0x50020000, 0xffffffff, 0), 916 SYSC_QUIRK("spinlock", 0, 0, 0x10, -1, 0x50020000, 0xffffffff, 0),
@@ -916,6 +918,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
916 SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0), 918 SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0),
917 SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, 919 SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
918 0xffffffff, 0), 920 0xffffffff, 0),
921 SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xffffffff, 0),
922 SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0d00, 0xffffffff, 0),
919#endif 923#endif
920}; 924};
921 925
diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
index 2efa3470a451..1ea3aab972b4 100644
--- a/include/linux/platform_data/ti-sysc.h
+++ b/include/linux/platform_data/ti-sysc.h
@@ -46,7 +46,6 @@ struct sysc_regbits {
46 s8 emufree_shift; 46 s8 emufree_shift;
47}; 47};
48 48
49#define SYSC_QUIRK_RESOURCE_PROVIDER BIT(9)
50#define SYSC_QUIRK_LEGACY_IDLE BIT(8) 49#define SYSC_QUIRK_LEGACY_IDLE BIT(8)
51#define SYSC_QUIRK_RESET_STATUS BIT(7) 50#define SYSC_QUIRK_RESET_STATUS BIT(7)
52#define SYSC_QUIRK_NO_IDLE_ON_INIT BIT(6) 51#define SYSC_QUIRK_NO_IDLE_ON_INIT BIT(6)