aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2011-10-19 17:52:50 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-10-21 18:20:12 -0400
commit382414b93ac1e8ee7693be710e60c83eacc97c6f (patch)
tree2b57a165a295af5468c611c553a9401a81f4b300
parentd93f5cdea968284f05aa9905ee9752874885a6fa (diff)
ARM: mach-shmobile: sh7372 A4R support (v4)
This change adds support for the sh7372 A4R power domain. The sh7372 A4R hardware power domain contains the SH CPU Core and a set of I/O devices including multimedia accelerators and I2C controllers. One special case about A4R is the INTCS interrupt controller that needs to be saved and restored to keep working as expected. Also the LCDC hardware blocks are in a different hardware power domain but have their IRQs routed only through INTCS. So as long as LCDCs are active we cannot power down INTCS because that would risk losing interrupts. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r--arch/arm/mach-shmobile/board-ap4evb.c1
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c1
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh7372.h7
-rw-r--r--arch/arm/mach-shmobile/intc-sh7372.c52
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c29
-rw-r--r--arch/arm/mach-shmobile/setup-sh7372.c8
6 files changed, 96 insertions, 2 deletions
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index bf4f6372dcf4..7e90d064ebcb 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -1412,6 +1412,7 @@ static void __init ap4evb_init(void)
1412 sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device); 1412 sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
1413 sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device); 1413 sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
1414 sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device); 1414 sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device);
1415 sh7372_add_device_to_domain(&sh7372_a4r, &ceu_device);
1415 1416
1416 hdmi_init_pm_clock(); 1417 hdmi_init_pm_clock();
1417 fsi_init_pm_clock(); 1418 fsi_init_pm_clock();
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index fdb1ca31dfe1..56d4fed6f03a 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -1596,6 +1596,7 @@ static void __init mackerel_init(void)
1596 sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device); 1596 sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device);
1597#endif 1597#endif
1598 sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi2_device); 1598 sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi2_device);
1599 sh7372_add_device_to_domain(&sh7372_a4r, &ceu_device);
1599 1600
1600 hdmi_init_pm_clock(); 1601 hdmi_init_pm_clock();
1601 sh7372_pm_init(); 1602 sh7372_pm_init();
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index 8542f2d31a56..84532f9629b2 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -480,8 +480,11 @@ struct platform_device;
480struct sh7372_pm_domain { 480struct sh7372_pm_domain {
481 struct generic_pm_domain genpd; 481 struct generic_pm_domain genpd;
482 struct dev_power_governor *gov; 482 struct dev_power_governor *gov;
483 void (*suspend)(void);
484 void (*resume)(void);
483 unsigned int bit_shift; 485 unsigned int bit_shift;
484 bool no_debug; 486 bool no_debug;
487 bool stay_on;
485}; 488};
486 489
487static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d) 490static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d)
@@ -493,6 +496,7 @@ static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d)
493extern struct sh7372_pm_domain sh7372_a4lc; 496extern struct sh7372_pm_domain sh7372_a4lc;
494extern struct sh7372_pm_domain sh7372_a4mp; 497extern struct sh7372_pm_domain sh7372_a4mp;
495extern struct sh7372_pm_domain sh7372_d4; 498extern struct sh7372_pm_domain sh7372_d4;
499extern struct sh7372_pm_domain sh7372_a4r;
496extern struct sh7372_pm_domain sh7372_a3rv; 500extern struct sh7372_pm_domain sh7372_a3rv;
497extern struct sh7372_pm_domain sh7372_a3ri; 501extern struct sh7372_pm_domain sh7372_a3ri;
498extern struct sh7372_pm_domain sh7372_a3sp; 502extern struct sh7372_pm_domain sh7372_a3sp;
@@ -509,4 +513,7 @@ extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
509#define sh7372_pm_add_subdomain(pd, sd) do { } while(0) 513#define sh7372_pm_add_subdomain(pd, sd) do { } while(0)
510#endif /* CONFIG_PM */ 514#endif /* CONFIG_PM */
511 515
516extern void sh7372_intcs_suspend(void);
517extern void sh7372_intcs_resume(void);
518
512#endif /* __ASM_SH7372_H__ */ 519#endif /* __ASM_SH7372_H__ */
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 739315e30eb9..29cdc0522d9c 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -606,9 +606,16 @@ static void intcs_demux(unsigned int irq, struct irq_desc *desc)
606 generic_handle_irq(intcs_evt2irq(evtcodeas)); 606 generic_handle_irq(intcs_evt2irq(evtcodeas));
607} 607}
608 608
609static void __iomem *intcs_ffd2;
610static void __iomem *intcs_ffd5;
611
609void __init sh7372_init_irq(void) 612void __init sh7372_init_irq(void)
610{ 613{
611 void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE); 614 void __iomem *intevtsa;
615
616 intcs_ffd2 = ioremap_nocache(0xffd20000, PAGE_SIZE);
617 intevtsa = intcs_ffd2 + 0x100;
618 intcs_ffd5 = ioremap_nocache(0xffd50000, PAGE_SIZE);
612 619
613 register_intc_controller(&intca_desc); 620 register_intc_controller(&intca_desc);
614 register_intc_controller(&intcs_desc); 621 register_intc_controller(&intcs_desc);
@@ -617,3 +624,46 @@ void __init sh7372_init_irq(void)
617 irq_set_handler_data(evt2irq(0xf80), (void *)intevtsa); 624 irq_set_handler_data(evt2irq(0xf80), (void *)intevtsa);
618 irq_set_chained_handler(evt2irq(0xf80), intcs_demux); 625 irq_set_chained_handler(evt2irq(0xf80), intcs_demux);
619} 626}
627
628static unsigned short ffd2[0x200];
629static unsigned short ffd5[0x100];
630
631void sh7372_intcs_suspend(void)
632{
633 int k;
634
635 for (k = 0x00; k <= 0x30; k += 4)
636 ffd2[k] = __raw_readw(intcs_ffd2 + k);
637
638 for (k = 0x80; k <= 0xb0; k += 4)
639 ffd2[k] = __raw_readb(intcs_ffd2 + k);
640
641 for (k = 0x180; k <= 0x188; k += 4)
642 ffd2[k] = __raw_readb(intcs_ffd2 + k);
643
644 for (k = 0x00; k <= 0x3c; k += 4)
645 ffd5[k] = __raw_readw(intcs_ffd5 + k);
646
647 for (k = 0x80; k <= 0x9c; k += 4)
648 ffd5[k] = __raw_readb(intcs_ffd5 + k);
649}
650
651void sh7372_intcs_resume(void)
652{
653 int k;
654
655 for (k = 0x00; k <= 0x30; k += 4)
656 __raw_writew(ffd2[k], intcs_ffd2 + k);
657
658 for (k = 0x80; k <= 0xb0; k += 4)
659 __raw_writeb(ffd2[k], intcs_ffd2 + k);
660
661 for (k = 0x180; k <= 0x188; k += 4)
662 __raw_writeb(ffd2[k], intcs_ffd2 + k);
663
664 for (k = 0x00; k <= 0x3c; k += 4)
665 __raw_writew(ffd5[k], intcs_ffd5 + k);
666
667 for (k = 0x80; k <= 0x9c; k += 4)
668 __raw_writeb(ffd5[k], intcs_ffd5 + k);
669}
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index fde619dd4c05..79612737c5b2 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -44,6 +44,7 @@
44#define SPDCR 0xe6180008 44#define SPDCR 0xe6180008
45#define SWUCR 0xe6180014 45#define SWUCR 0xe6180014
46#define SBAR 0xe6180020 46#define SBAR 0xe6180020
47#define WUPRMSK 0xe6180028
47#define WUPSMSK 0xe618002c 48#define WUPSMSK 0xe618002c
48#define WUPSMSK2 0xe6180048 49#define WUPSMSK2 0xe6180048
49#define PSTR 0xe6180080 50#define PSTR 0xe6180080
@@ -80,6 +81,12 @@ static int pd_power_down(struct generic_pm_domain *genpd)
80 struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd); 81 struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd);
81 unsigned int mask = 1 << sh7372_pd->bit_shift; 82 unsigned int mask = 1 << sh7372_pd->bit_shift;
82 83
84 if (sh7372_pd->suspend)
85 sh7372_pd->suspend();
86
87 if (sh7372_pd->stay_on)
88 return 0;
89
83 if (__raw_readl(PSTR) & mask) { 90 if (__raw_readl(PSTR) & mask) {
84 unsigned int retry_count; 91 unsigned int retry_count;
85 92
@@ -106,6 +113,9 @@ static int pd_power_up(struct generic_pm_domain *genpd)
106 unsigned int retry_count; 113 unsigned int retry_count;
107 int ret = 0; 114 int ret = 0;
108 115
116 if (sh7372_pd->stay_on)
117 goto out;
118
109 if (__raw_readl(PSTR) & mask) 119 if (__raw_readl(PSTR) & mask)
110 goto out; 120 goto out;
111 121
@@ -122,14 +132,23 @@ static int pd_power_up(struct generic_pm_domain *genpd)
122 if (__raw_readl(SWUCR) & mask) 132 if (__raw_readl(SWUCR) & mask)
123 ret = -EIO; 133 ret = -EIO;
124 134
125 out:
126 if (!sh7372_pd->no_debug) 135 if (!sh7372_pd->no_debug)
127 pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n", 136 pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n",
128 mask, __raw_readl(PSTR)); 137 mask, __raw_readl(PSTR));
129 138
139 out:
140 if (ret == 0 && sh7372_pd->resume)
141 sh7372_pd->resume();
142
130 return ret; 143 return ret;
131} 144}
132 145
146static void sh7372_a4r_suspend(void)
147{
148 sh7372_intcs_suspend();
149 __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */
150}
151
133static bool pd_active_wakeup(struct device *dev) 152static bool pd_active_wakeup(struct device *dev)
134{ 153{
135 return true; 154 return true;
@@ -186,6 +205,14 @@ struct sh7372_pm_domain sh7372_d4 = {
186 .bit_shift = 3, 205 .bit_shift = 3,
187}; 206};
188 207
208struct sh7372_pm_domain sh7372_a4r = {
209 .bit_shift = 5,
210 .gov = &sh7372_always_on_gov,
211 .suspend = sh7372_a4r_suspend,
212 .resume = sh7372_intcs_resume,
213 .stay_on = true,
214};
215
189struct sh7372_pm_domain sh7372_a3rv = { 216struct sh7372_pm_domain sh7372_a3rv = {
190 .bit_shift = 6, 217 .bit_shift = 6,
191}; 218};
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index 5f1afcc4de6e..2380389e6ac5 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -991,12 +991,14 @@ void __init sh7372_add_standard_devices(void)
991 sh7372_init_pm_domain(&sh7372_a4lc); 991 sh7372_init_pm_domain(&sh7372_a4lc);
992 sh7372_init_pm_domain(&sh7372_a4mp); 992 sh7372_init_pm_domain(&sh7372_a4mp);
993 sh7372_init_pm_domain(&sh7372_d4); 993 sh7372_init_pm_domain(&sh7372_d4);
994 sh7372_init_pm_domain(&sh7372_a4r);
994 sh7372_init_pm_domain(&sh7372_a3rv); 995 sh7372_init_pm_domain(&sh7372_a3rv);
995 sh7372_init_pm_domain(&sh7372_a3ri); 996 sh7372_init_pm_domain(&sh7372_a3ri);
996 sh7372_init_pm_domain(&sh7372_a3sg); 997 sh7372_init_pm_domain(&sh7372_a3sg);
997 sh7372_init_pm_domain(&sh7372_a3sp); 998 sh7372_init_pm_domain(&sh7372_a3sp);
998 999
999 sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv); 1000 sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
1001 sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc);
1000 1002
1001 platform_add_devices(sh7372_early_devices, 1003 platform_add_devices(sh7372_early_devices,
1002 ARRAY_SIZE(sh7372_early_devices)); 1004 ARRAY_SIZE(sh7372_early_devices));
@@ -1020,6 +1022,12 @@ void __init sh7372_add_standard_devices(void)
1020 sh7372_add_device_to_domain(&sh7372_a3sp, &dma2_device); 1022 sh7372_add_device_to_domain(&sh7372_a3sp, &dma2_device);
1021 sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma0_device); 1023 sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma0_device);
1022 sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma1_device); 1024 sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma1_device);
1025 sh7372_add_device_to_domain(&sh7372_a4r, &iic0_device);
1026 sh7372_add_device_to_domain(&sh7372_a4r, &veu0_device);
1027 sh7372_add_device_to_domain(&sh7372_a4r, &veu1_device);
1028 sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device);
1029 sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device);
1030 sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device);
1023} 1031}
1024 1032
1025void __init sh7372_add_early_devices(void) 1033void __init sh7372_add_early_devices(void)