uniphier-system-bus.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
  4. */
  5. #include <linux/io.h>
  6. #include <linux/log2.h>
  7. #include <linux/module.h>
  8. #include <linux/of.h>
  9. #include <linux/of_address.h>
  10. #include <linux/of_platform.h>
  11. #include <linux/platform_device.h>
  12. /* System Bus Controller registers */
  13. #define UNIPHIER_SBC_BASE 0x100 /* base address of bank0 space */
  14. #define UNIPHIER_SBC_BASE_BE BIT(0) /* bank_enable */
  15. #define UNIPHIER_SBC_CTRL0 0x200 /* timing parameter 0 of bank0 */
  16. #define UNIPHIER_SBC_CTRL1 0x204 /* timing parameter 1 of bank0 */
  17. #define UNIPHIER_SBC_CTRL2 0x208 /* timing parameter 2 of bank0 */
  18. #define UNIPHIER_SBC_CTRL3 0x20c /* timing parameter 3 of bank0 */
  19. #define UNIPHIER_SBC_CTRL4 0x300 /* timing parameter 4 of bank0 */
  20. #define UNIPHIER_SBC_STRIDE 0x10 /* register stride to next bank */
  21. #define UNIPHIER_SBC_NR_BANKS 8 /* number of banks (chip select) */
  22. #define UNIPHIER_SBC_BASE_DUMMY 0xffffffff /* data to squash bank 0, 1 */
  23. struct uniphier_system_bus_bank {
  24. u32 base;
  25. u32 end;
  26. };
  27. struct uniphier_system_bus_priv {
  28. struct device *dev;
  29. void __iomem *membase;
  30. struct uniphier_system_bus_bank bank[UNIPHIER_SBC_NR_BANKS];
  31. };
  32. static int uniphier_system_bus_add_bank(struct uniphier_system_bus_priv *priv,
  33. int bank, u32 addr, u64 paddr, u32 size)
  34. {
  35. u64 end, mask;
  36. dev_dbg(priv->dev,
  37. "range found: bank = %d, addr = %08x, paddr = %08llx, size = %08x\n",
  38. bank, addr, paddr, size);
  39. if (bank >= ARRAY_SIZE(priv->bank)) {
  40. dev_err(priv->dev, "unsupported bank number %d\n", bank);
  41. return -EINVAL;
  42. }
  43. if (priv->bank[bank].base || priv->bank[bank].end) {
  44. dev_err(priv->dev,
  45. "range for bank %d has already been specified\n", bank);
  46. return -EINVAL;
  47. }
  48. if (paddr > U32_MAX) {
  49. dev_err(priv->dev, "base address %llx is too high\n", paddr);
  50. return -EINVAL;
  51. }
  52. end = paddr + size;
  53. if (addr > paddr) {
  54. dev_err(priv->dev,
  55. "base %08x cannot be mapped to %08llx of parent\n",
  56. addr, paddr);
  57. return -EINVAL;
  58. }
  59. paddr -= addr;
  60. paddr = round_down(paddr, 0x00020000);
  61. end = round_up(end, 0x00020000);
  62. if (end > U32_MAX) {
  63. dev_err(priv->dev, "end address %08llx is too high\n", end);
  64. return -EINVAL;
  65. }
  66. mask = paddr ^ (end - 1);
  67. mask = roundup_pow_of_two(mask);
  68. paddr = round_down(paddr, mask);
  69. end = round_up(end, mask);
  70. priv->bank[bank].base = paddr;
  71. priv->bank[bank].end = end;
  72. dev_dbg(priv->dev, "range added: bank = %d, addr = %08x, end = %08x\n",
  73. bank, priv->bank[bank].base, priv->bank[bank].end);
  74. return 0;
  75. }
  76. static int uniphier_system_bus_check_overlap(
  77. const struct uniphier_system_bus_priv *priv)
  78. {
  79. int i, j;
  80. for (i = 0; i < ARRAY_SIZE(priv->bank); i++) {
  81. for (j = i + 1; j < ARRAY_SIZE(priv->bank); j++) {
  82. if (priv->bank[i].end > priv->bank[j].base &&
  83. priv->bank[i].base < priv->bank[j].end) {
  84. dev_err(priv->dev,
  85. "region overlap between bank%d and bank%d\n",
  86. i, j);
  87. return -EINVAL;
  88. }
  89. }
  90. }
  91. return 0;
  92. }
  93. static void uniphier_system_bus_check_boot_swap(
  94. struct uniphier_system_bus_priv *priv)
  95. {
  96. void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE;
  97. int is_swapped;
  98. is_swapped = !(readl(base_reg) & UNIPHIER_SBC_BASE_BE);
  99. dev_dbg(priv->dev, "Boot Swap: %s\n", is_swapped ? "on" : "off");
  100. /*
  101. * If BOOT_SWAP was asserted on power-on-reset, the CS0 and CS1 are
  102. * swapped. In this case, bank0 and bank1 should be swapped as well.
  103. */
  104. if (is_swapped)
  105. swap(priv->bank[0], priv->bank[1]);
  106. }
  107. static void uniphier_system_bus_set_reg(
  108. const struct uniphier_system_bus_priv *priv)
  109. {
  110. void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE;
  111. u32 base, end, mask, val;
  112. int i;
  113. for (i = 0; i < ARRAY_SIZE(priv->bank); i++) {
  114. base = priv->bank[i].base;
  115. end = priv->bank[i].end;
  116. if (base == end) {
  117. /*
  118. * If SBC_BASE0 or SBC_BASE1 is set to zero, the access
  119. * to anywhere in the system bus space is routed to
  120. * bank 0 (if boot swap if off) or bank 1 (if boot swap
  121. * if on). It means that CPUs cannot get access to
  122. * bank 2 or later. In other words, bank 0/1 cannot
  123. * be disabled even if its bank_enable bits is cleared.
  124. * This seems odd, but it is how this hardware goes.
  125. * As a workaround, dummy data (0xffffffff) should be
  126. * set when the bank 0/1 is unused. As for bank 2 and
  127. * later, they can be simply disable by clearing the
  128. * bank_enable bit.
  129. */
  130. if (i < 2)
  131. val = UNIPHIER_SBC_BASE_DUMMY;
  132. else
  133. val = 0;
  134. } else {
  135. mask = base ^ (end - 1);
  136. val = base & 0xfffe0000;
  137. val |= (~mask >> 16) & 0xfffe;
  138. val |= UNIPHIER_SBC_BASE_BE;
  139. }
  140. dev_dbg(priv->dev, "SBC_BASE[%d] = 0x%08x\n", i, val);
  141. writel(val, base_reg + UNIPHIER_SBC_STRIDE * i);
  142. }
  143. }
  144. static int uniphier_system_bus_probe(struct platform_device *pdev)
  145. {
  146. struct device *dev = &pdev->dev;
  147. struct uniphier_system_bus_priv *priv;
  148. struct of_range_parser parser;
  149. struct of_range range;
  150. int ret;
  151. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  152. if (!priv)
  153. return -ENOMEM;
  154. priv->membase = devm_platform_ioremap_resource(pdev, 0);
  155. if (IS_ERR(priv->membase))
  156. return PTR_ERR(priv->membase);
  157. priv->dev = dev;
  158. ret = of_range_parser_init(&parser, dev->of_node);
  159. if (ret)
  160. return ret;
  161. for_each_of_range(&parser, &range) {
  162. if (range.cpu_addr == OF_BAD_ADDR)
  163. return -EINVAL;
  164. ret = uniphier_system_bus_add_bank(priv,
  165. upper_32_bits(range.bus_addr),
  166. lower_32_bits(range.bus_addr),
  167. range.cpu_addr, range.size);
  168. if (ret)
  169. return ret;
  170. }
  171. ret = uniphier_system_bus_check_overlap(priv);
  172. if (ret)
  173. return ret;
  174. uniphier_system_bus_check_boot_swap(priv);
  175. uniphier_system_bus_set_reg(priv);
  176. platform_set_drvdata(pdev, priv);
  177. /* Now, the bus is configured. Populate platform_devices below it */
  178. return of_platform_default_populate(dev->of_node, NULL, dev);
  179. }
  180. static int __maybe_unused uniphier_system_bus_resume(struct device *dev)
  181. {
  182. uniphier_system_bus_set_reg(dev_get_drvdata(dev));
  183. return 0;
  184. }
  185. static const struct dev_pm_ops uniphier_system_bus_pm_ops = {
  186. SET_SYSTEM_SLEEP_PM_OPS(NULL, uniphier_system_bus_resume)
  187. };
  188. static const struct of_device_id uniphier_system_bus_match[] = {
  189. { .compatible = "socionext,uniphier-system-bus" },
  190. { /* sentinel */ }
  191. };
  192. MODULE_DEVICE_TABLE(of, uniphier_system_bus_match);
  193. static struct platform_driver uniphier_system_bus_driver = {
  194. .probe = uniphier_system_bus_probe,
  195. .driver = {
  196. .name = "uniphier-system-bus",
  197. .of_match_table = uniphier_system_bus_match,
  198. .pm = &uniphier_system_bus_pm_ops,
  199. },
  200. };
  201. module_platform_driver(uniphier_system_bus_driver);
  202. MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
  203. MODULE_DESCRIPTION("UniPhier System Bus driver");
  204. MODULE_LICENSE("GPL");