pm-r8a7779.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*
  2. * r8a7779 Power management support
  3. *
  4. * Copyright (C) 2011 Renesas Solutions Corp.
  5. * Copyright (C) 2011 Magnus Damm
  6. *
  7. * This file is subject to the terms and conditions of the GNU General Public
  8. * License. See the file "COPYING" in the main directory of this archive
  9. * for more details.
  10. */
  11. #include <linux/pm.h>
  12. #include <linux/suspend.h>
  13. #include <linux/err.h>
  14. #include <linux/pm_clock.h>
  15. #include <linux/pm_domain.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/delay.h>
  18. #include <linux/irq.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/console.h>
  21. #include <asm/io.h>
  22. #include "common.h"
  23. #include "pm-rcar.h"
  24. #include "r8a7779.h"
  25. /* SYSC */
  26. #define SYSCIER 0x0c
  27. #define SYSCIMR 0x10
  28. struct r8a7779_pm_domain {
  29. struct generic_pm_domain genpd;
  30. struct rcar_sysc_ch ch;
  31. };
  32. static inline struct rcar_sysc_ch *to_r8a7779_ch(struct generic_pm_domain *d)
  33. {
  34. return &container_of(d, struct r8a7779_pm_domain, genpd)->ch;
  35. }
  36. #if defined(CONFIG_PM) || defined(CONFIG_SMP)
  37. static void __init r8a7779_sysc_init(void)
  38. {
  39. void __iomem *base = rcar_sysc_init(0xffd85000);
  40. /* enable all interrupt sources, but do not use interrupt handler */
  41. iowrite32(0x0131000e, base + SYSCIER);
  42. iowrite32(0, base + SYSCIMR);
  43. }
  44. #else /* CONFIG_PM || CONFIG_SMP */
  45. static inline void r8a7779_sysc_init(void) {}
  46. #endif /* CONFIG_PM || CONFIG_SMP */
  47. #ifdef CONFIG_PM
  48. static int pd_power_down(struct generic_pm_domain *genpd)
  49. {
  50. return rcar_sysc_power_down(to_r8a7779_ch(genpd));
  51. }
  52. static int pd_power_up(struct generic_pm_domain *genpd)
  53. {
  54. return rcar_sysc_power_up(to_r8a7779_ch(genpd));
  55. }
  56. static bool pd_is_off(struct generic_pm_domain *genpd)
  57. {
  58. return rcar_sysc_power_is_off(to_r8a7779_ch(genpd));
  59. }
  60. static bool pd_active_wakeup(struct device *dev)
  61. {
  62. return true;
  63. }
  64. static void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
  65. {
  66. struct generic_pm_domain *genpd = &r8a7779_pd->genpd;
  67. genpd->flags = GENPD_FLAG_PM_CLK;
  68. pm_genpd_init(genpd, NULL, false);
  69. genpd->dev_ops.active_wakeup = pd_active_wakeup;
  70. genpd->power_off = pd_power_down;
  71. genpd->power_on = pd_power_up;
  72. if (pd_is_off(&r8a7779_pd->genpd))
  73. pd_power_up(&r8a7779_pd->genpd);
  74. }
  75. static struct r8a7779_pm_domain r8a7779_pm_domains[] = {
  76. {
  77. .genpd.name = "SH4A",
  78. .ch = {
  79. .chan_offs = 0x80, /* PWRSR1 .. PWRER1 */
  80. .isr_bit = 16, /* SH4A */
  81. },
  82. },
  83. {
  84. .genpd.name = "SGX",
  85. .ch = {
  86. .chan_offs = 0xc0, /* PWRSR2 .. PWRER2 */
  87. .isr_bit = 20, /* SGX */
  88. },
  89. },
  90. {
  91. .genpd.name = "VDP1",
  92. .ch = {
  93. .chan_offs = 0x100, /* PWRSR3 .. PWRER3 */
  94. .isr_bit = 21, /* VDP */
  95. },
  96. },
  97. {
  98. .genpd.name = "IMPX3",
  99. .ch = {
  100. .chan_offs = 0x140, /* PWRSR4 .. PWRER4 */
  101. .isr_bit = 24, /* IMP */
  102. },
  103. },
  104. };
  105. void __init r8a7779_init_pm_domains(void)
  106. {
  107. int j;
  108. for (j = 0; j < ARRAY_SIZE(r8a7779_pm_domains); j++)
  109. r8a7779_init_pm_domain(&r8a7779_pm_domains[j]);
  110. }
  111. #endif /* CONFIG_PM */
  112. void __init r8a7779_pm_init(void)
  113. {
  114. static int once;
  115. if (!once++)
  116. r8a7779_sysc_init();
  117. }