pm-rcar.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * R-Car SYSC Power management support
  3. *
  4. * Copyright (C) 2014 Magnus Damm
  5. *
  6. * This file is subject to the terms and conditions of the GNU General Public
  7. * License. See the file "COPYING" in the main directory of this archive
  8. * for more details.
  9. */
  10. #include <linux/delay.h>
  11. #include <linux/err.h>
  12. #include <linux/mm.h>
  13. #include <linux/spinlock.h>
  14. #include <linux/io.h>
  15. #include "pm-rcar.h"
  16. /* SYSC Common */
  17. #define SYSCSR 0x00 /* SYSC Status Register */
  18. #define SYSCISR 0x04 /* Interrupt Status Register */
  19. #define SYSCISCR 0x08 /* Interrupt Status Clear Register */
  20. #define SYSCIER 0x0c /* Interrupt Enable Register */
  21. #define SYSCIMR 0x10 /* Interrupt Mask Register */
  22. /* SYSC Status Register */
  23. #define SYSCSR_PONENB 1 /* Ready for power resume requests */
  24. #define SYSCSR_POFFENB 0 /* Ready for power shutoff requests */
  25. /*
  26. * Power Control Register Offsets inside the register block for each domain
  27. * Note: The "CR" registers for ARM cores exist on H1 only
  28. * Use WFI to power off, CPG/APMU to resume ARM cores on R-Car Gen2
  29. */
  30. #define PWRSR_OFFS 0x00 /* Power Status Register */
  31. #define PWROFFCR_OFFS 0x04 /* Power Shutoff Control Register */
  32. #define PWROFFSR_OFFS 0x08 /* Power Shutoff Status Register */
  33. #define PWRONCR_OFFS 0x0c /* Power Resume Control Register */
  34. #define PWRONSR_OFFS 0x10 /* Power Resume Status Register */
  35. #define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */
  36. #define SYSCSR_RETRIES 100
  37. #define SYSCSR_DELAY_US 1
  38. #define PWRER_RETRIES 100
  39. #define PWRER_DELAY_US 1
  40. #define SYSCISR_RETRIES 1000
  41. #define SYSCISR_DELAY_US 1
  42. static void __iomem *rcar_sysc_base;
  43. static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
  44. static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on)
  45. {
  46. unsigned int sr_bit, reg_offs;
  47. int k;
  48. if (on) {
  49. sr_bit = SYSCSR_PONENB;
  50. reg_offs = PWRONCR_OFFS;
  51. } else {
  52. sr_bit = SYSCSR_POFFENB;
  53. reg_offs = PWROFFCR_OFFS;
  54. }
  55. /* Wait until SYSC is ready to accept a power request */
  56. for (k = 0; k < SYSCSR_RETRIES; k++) {
  57. if (ioread32(rcar_sysc_base + SYSCSR) & BIT(sr_bit))
  58. break;
  59. udelay(SYSCSR_DELAY_US);
  60. }
  61. if (k == SYSCSR_RETRIES)
  62. return -EAGAIN;
  63. /* Submit power shutoff or power resume request */
  64. iowrite32(BIT(sysc_ch->chan_bit),
  65. rcar_sysc_base + sysc_ch->chan_offs + reg_offs);
  66. return 0;
  67. }
  68. static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
  69. {
  70. unsigned int isr_mask = BIT(sysc_ch->isr_bit);
  71. unsigned int chan_mask = BIT(sysc_ch->chan_bit);
  72. unsigned int status;
  73. unsigned long flags;
  74. int ret = 0;
  75. int k;
  76. spin_lock_irqsave(&rcar_sysc_lock, flags);
  77. iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
  78. /* Submit power shutoff or resume request until it was accepted */
  79. for (k = 0; k < PWRER_RETRIES; k++) {
  80. ret = rcar_sysc_pwr_on_off(sysc_ch, on);
  81. if (ret)
  82. goto out;
  83. status = ioread32(rcar_sysc_base +
  84. sysc_ch->chan_offs + PWRER_OFFS);
  85. if (!(status & chan_mask))
  86. break;
  87. udelay(PWRER_DELAY_US);
  88. }
  89. if (k == PWRER_RETRIES) {
  90. ret = -EIO;
  91. goto out;
  92. }
  93. /* Wait until the power shutoff or resume request has completed * */
  94. for (k = 0; k < SYSCISR_RETRIES; k++) {
  95. if (ioread32(rcar_sysc_base + SYSCISR) & isr_mask)
  96. break;
  97. udelay(SYSCISR_DELAY_US);
  98. }
  99. if (k == SYSCISR_RETRIES)
  100. ret = -EIO;
  101. iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
  102. out:
  103. spin_unlock_irqrestore(&rcar_sysc_lock, flags);
  104. pr_debug("sysc power domain %d: %08x -> %d\n",
  105. sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret);
  106. return ret;
  107. }
  108. int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch)
  109. {
  110. return rcar_sysc_power(sysc_ch, false);
  111. }
  112. int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch)
  113. {
  114. return rcar_sysc_power(sysc_ch, true);
  115. }
  116. bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch)
  117. {
  118. unsigned int st;
  119. st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS);
  120. if (st & BIT(sysc_ch->chan_bit))
  121. return true;
  122. return false;
  123. }
  124. void __iomem *rcar_sysc_init(phys_addr_t base)
  125. {
  126. rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE);
  127. if (!rcar_sysc_base)
  128. panic("unable to ioremap R-Car SYSC hardware block\n");
  129. return rcar_sysc_base;
  130. }