bcm63xx_pmb.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*
  2. * Broadcom BCM63138 PMB initialization for secondary CPU(s)
  3. *
  4. * Copyright (C) 2015 Broadcom Corporation
  5. * Author: Florian Fainelli <f.fainelli@gmail.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/io.h>
  14. #include <linux/spinlock.h>
  15. #include <linux/reset/bcm63xx_pmb.h>
  16. #include <linux/of.h>
  17. #include <linux/of_address.h>
  18. #include "bcm63xx_smp.h"
  19. /* ARM Control register definitions */
  20. #define CORE_PWR_CTRL_SHIFT 0
  21. #define CORE_PWR_CTRL_MASK 0x3
  22. #define PLL_PWR_ON BIT(8)
  23. #define PLL_LDO_PWR_ON BIT(9)
  24. #define PLL_CLAMP_ON BIT(10)
  25. #define CPU_RESET_N(x) BIT(13 + (x))
  26. #define NEON_RESET_N BIT(15)
  27. #define PWR_CTRL_STATUS_SHIFT 28
  28. #define PWR_CTRL_STATUS_MASK 0x3
  29. #define PWR_DOWN_SHIFT 30
  30. #define PWR_DOWN_MASK 0x3
  31. /* CPU Power control register definitions */
  32. #define MEM_PWR_OK BIT(0)
  33. #define MEM_PWR_ON BIT(1)
  34. #define MEM_CLAMP_ON BIT(2)
  35. #define MEM_PWR_OK_STATUS BIT(4)
  36. #define MEM_PWR_ON_STATUS BIT(5)
  37. #define MEM_PDA_SHIFT 8
  38. #define MEM_PDA_MASK 0xf
  39. #define MEM_PDA_CPU_MASK 0x1
  40. #define MEM_PDA_NEON_MASK 0xf
  41. #define CLAMP_ON BIT(15)
  42. #define PWR_OK_SHIFT 16
  43. #define PWR_OK_MASK 0xf
  44. #define PWR_ON_SHIFT 20
  45. #define PWR_CPU_MASK 0x03
  46. #define PWR_NEON_MASK 0x01
  47. #define PWR_ON_MASK 0xf
  48. #define PWR_OK_STATUS_SHIFT 24
  49. #define PWR_OK_STATUS_MASK 0xf
  50. #define PWR_ON_STATUS_SHIFT 28
  51. #define PWR_ON_STATUS_MASK 0xf
  52. #define ARM_CONTROL 0x30
  53. #define ARM_PWR_CONTROL_BASE 0x34
  54. #define ARM_PWR_CONTROL(x) (ARM_PWR_CONTROL_BASE + (x) * 0x4)
  55. #define ARM_NEON_L2 0x3c
  56. /* Perform a value write, then spin until the value shifted by
  57. * shift is seen, masked with mask and is different from cond.
  58. */
  59. static int bpcm_wr_rd_mask(void __iomem *master,
  60. unsigned int addr, u32 off, u32 *val,
  61. u32 shift, u32 mask, u32 cond)
  62. {
  63. int ret;
  64. ret = bpcm_wr(master, addr, off, *val);
  65. if (ret)
  66. return ret;
  67. do {
  68. ret = bpcm_rd(master, addr, off, val);
  69. if (ret)
  70. return ret;
  71. cpu_relax();
  72. } while (((*val >> shift) & mask) != cond);
  73. return ret;
  74. }
  75. /* Global lock to serialize accesses to the PMB registers while we
  76. * are bringing up the secondary CPU
  77. */
  78. static DEFINE_SPINLOCK(pmb_lock);
  79. static int bcm63xx_pmb_get_resources(struct device_node *dn,
  80. void __iomem **base,
  81. unsigned int *cpu,
  82. unsigned int *addr)
  83. {
  84. struct of_phandle_args args;
  85. int ret;
  86. ret = of_property_read_u32(dn, "reg", cpu);
  87. if (ret) {
  88. pr_err("CPU is missing a reg node\n");
  89. return ret;
  90. }
  91. ret = of_parse_phandle_with_args(dn, "resets", "#reset-cells",
  92. 0, &args);
  93. if (ret) {
  94. pr_err("CPU is missing a resets phandle\n");
  95. return ret;
  96. }
  97. if (args.args_count != 2) {
  98. pr_err("reset-controller does not conform to reset-cells\n");
  99. return -EINVAL;
  100. }
  101. *base = of_iomap(args.np, 0);
  102. if (!*base) {
  103. pr_err("failed remapping PMB register\n");
  104. return -ENOMEM;
  105. }
  106. /* We do not need the number of zones */
  107. *addr = args.args[0];
  108. return 0;
  109. }
  110. int bcm63xx_pmb_power_on_cpu(struct device_node *dn)
  111. {
  112. void __iomem *base;
  113. unsigned int cpu, addr;
  114. unsigned long flags;
  115. u32 val, ctrl;
  116. int ret;
  117. ret = bcm63xx_pmb_get_resources(dn, &base, &cpu, &addr);
  118. if (ret)
  119. return ret;
  120. /* We would not know how to enable a third and greater CPU */
  121. WARN_ON(cpu > 1);
  122. spin_lock_irqsave(&pmb_lock, flags);
  123. /* Check if the CPU is already on and save the ARM_CONTROL register
  124. * value since we will use it later for CPU de-assert once done with
  125. * the CPU-specific power sequence
  126. */
  127. ret = bpcm_rd(base, addr, ARM_CONTROL, &ctrl);
  128. if (ret)
  129. goto out;
  130. if (ctrl & CPU_RESET_N(cpu)) {
  131. pr_info("PMB: CPU%d is already powered on\n", cpu);
  132. ret = 0;
  133. goto out;
  134. }
  135. /* Power on PLL */
  136. ret = bpcm_rd(base, addr, ARM_PWR_CONTROL(cpu), &val);
  137. if (ret)
  138. goto out;
  139. val |= (PWR_CPU_MASK << PWR_ON_SHIFT);
  140. ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
  141. PWR_ON_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK);
  142. if (ret)
  143. goto out;
  144. val |= (PWR_CPU_MASK << PWR_OK_SHIFT);
  145. ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
  146. PWR_OK_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK);
  147. if (ret)
  148. goto out;
  149. val &= ~CLAMP_ON;
  150. ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
  151. if (ret)
  152. goto out;
  153. /* Power on CPU<N> RAM */
  154. val &= ~(MEM_PDA_MASK << MEM_PDA_SHIFT);
  155. ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
  156. if (ret)
  157. goto out;
  158. val |= MEM_PWR_ON;
  159. ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
  160. 0, MEM_PWR_ON_STATUS, MEM_PWR_ON_STATUS);
  161. if (ret)
  162. goto out;
  163. val |= MEM_PWR_OK;
  164. ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
  165. 0, MEM_PWR_OK_STATUS, MEM_PWR_OK_STATUS);
  166. if (ret)
  167. goto out;
  168. val &= ~MEM_CLAMP_ON;
  169. ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
  170. if (ret)
  171. goto out;
  172. /* De-assert CPU reset */
  173. ctrl |= CPU_RESET_N(cpu);
  174. ret = bpcm_wr(base, addr, ARM_CONTROL, ctrl);
  175. out:
  176. spin_unlock_irqrestore(&pmb_lock, flags);
  177. iounmap(base);
  178. return ret;
  179. }