ip30-xtalk.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * ip30-xtalk.c - Very basic Crosstalk (XIO) detection support.
  4. * Copyright (C) 2004-2007 Stanislaw Skowronek <[email protected]>
  5. * Copyright (C) 2009 Johannes Dickgreber <[email protected]>
  6. * Copyright (C) 2007, 2014-2016 Joshua Kinard <[email protected]>
  7. */
  8. #include <linux/init.h>
  9. #include <linux/kernel.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/platform_data/sgi-w1.h>
  12. #include <linux/platform_data/xtalk-bridge.h>
  13. #include <asm/xtalk/xwidget.h>
  14. #include <asm/pci/bridge.h>
  15. #define IP30_SWIN_BASE(widget) \
  16. (0x0000000010000000 | (((unsigned long)(widget)) << 24))
  17. #define IP30_RAW_SWIN_BASE(widget) (IO_BASE + IP30_SWIN_BASE(widget))
  18. #define IP30_SWIN_SIZE (1 << 24)
  19. #define IP30_WIDGET_XBOW _AC(0x0, UL) /* XBow is always 0 */
  20. #define IP30_WIDGET_HEART _AC(0x8, UL) /* HEART is always 8 */
  21. #define IP30_WIDGET_PCI_BASE _AC(0xf, UL) /* BaseIO PCI is always 15 */
  22. #define XTALK_NODEV 0xffffffff
  23. #define XBOW_REG_LINK_STAT_0 0x114
  24. #define XBOW_REG_LINK_BLK_SIZE 0x40
  25. #define XBOW_REG_LINK_ALIVE 0x80000000
  26. #define HEART_INTR_ADDR 0x00000080
  27. #define xtalk_read __raw_readl
  28. static void bridge_platform_create(int widget, int masterwid)
  29. {
  30. struct xtalk_bridge_platform_data *bd;
  31. struct sgi_w1_platform_data *wd;
  32. struct platform_device *pdev_wd;
  33. struct platform_device *pdev_bd;
  34. struct resource w1_res;
  35. wd = kzalloc(sizeof(*wd), GFP_KERNEL);
  36. if (!wd) {
  37. pr_warn("xtalk:%x bridge create out of memory\n", widget);
  38. return;
  39. }
  40. snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
  41. IP30_SWIN_BASE(widget));
  42. memset(&w1_res, 0, sizeof(w1_res));
  43. w1_res.start = IP30_SWIN_BASE(widget) +
  44. offsetof(struct bridge_regs, b_nic);
  45. w1_res.end = w1_res.start + 3;
  46. w1_res.flags = IORESOURCE_MEM;
  47. pdev_wd = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
  48. if (!pdev_wd) {
  49. pr_warn("xtalk:%x bridge create out of memory\n", widget);
  50. goto err_kfree_wd;
  51. }
  52. if (platform_device_add_resources(pdev_wd, &w1_res, 1)) {
  53. pr_warn("xtalk:%x bridge failed to add platform resources.\n", widget);
  54. goto err_put_pdev_wd;
  55. }
  56. if (platform_device_add_data(pdev_wd, wd, sizeof(*wd))) {
  57. pr_warn("xtalk:%x bridge failed to add platform data.\n", widget);
  58. goto err_put_pdev_wd;
  59. }
  60. if (platform_device_add(pdev_wd)) {
  61. pr_warn("xtalk:%x bridge failed to add platform device.\n", widget);
  62. goto err_put_pdev_wd;
  63. }
  64. /* platform_device_add_data() duplicates the data */
  65. kfree(wd);
  66. bd = kzalloc(sizeof(*bd), GFP_KERNEL);
  67. if (!bd) {
  68. pr_warn("xtalk:%x bridge create out of memory\n", widget);
  69. goto err_unregister_pdev_wd;
  70. }
  71. pdev_bd = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
  72. if (!pdev_bd) {
  73. pr_warn("xtalk:%x bridge create out of memory\n", widget);
  74. goto err_kfree_bd;
  75. }
  76. bd->bridge_addr = IP30_RAW_SWIN_BASE(widget);
  77. bd->intr_addr = HEART_INTR_ADDR;
  78. bd->nasid = 0;
  79. bd->masterwid = masterwid;
  80. bd->mem.name = "Bridge PCI MEM";
  81. bd->mem.start = IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
  82. bd->mem.end = IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
  83. bd->mem.flags = IORESOURCE_MEM;
  84. bd->mem_offset = IP30_SWIN_BASE(widget);
  85. bd->io.name = "Bridge PCI IO";
  86. bd->io.start = IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
  87. bd->io.end = IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
  88. bd->io.flags = IORESOURCE_IO;
  89. bd->io_offset = IP30_SWIN_BASE(widget);
  90. if (platform_device_add_data(pdev_bd, bd, sizeof(*bd))) {
  91. pr_warn("xtalk:%x bridge failed to add platform data.\n", widget);
  92. goto err_put_pdev_bd;
  93. }
  94. if (platform_device_add(pdev_bd)) {
  95. pr_warn("xtalk:%x bridge failed to add platform device.\n", widget);
  96. goto err_put_pdev_bd;
  97. }
  98. /* platform_device_add_data() duplicates the data */
  99. kfree(bd);
  100. pr_info("xtalk:%x bridge widget\n", widget);
  101. return;
  102. err_put_pdev_bd:
  103. platform_device_put(pdev_bd);
  104. err_kfree_bd:
  105. kfree(bd);
  106. err_unregister_pdev_wd:
  107. platform_device_unregister(pdev_wd);
  108. return;
  109. err_put_pdev_wd:
  110. platform_device_put(pdev_wd);
  111. err_kfree_wd:
  112. kfree(wd);
  113. return;
  114. }
  115. static unsigned int __init xbow_widget_active(s8 wid)
  116. {
  117. unsigned int link_stat;
  118. link_stat = xtalk_read((void *)(IP30_RAW_SWIN_BASE(IP30_WIDGET_XBOW) +
  119. XBOW_REG_LINK_STAT_0 +
  120. XBOW_REG_LINK_BLK_SIZE *
  121. (wid - 8)));
  122. return (link_stat & XBOW_REG_LINK_ALIVE) ? 1 : 0;
  123. }
  124. static void __init xtalk_init_widget(s8 wid, s8 masterwid)
  125. {
  126. xwidget_part_num_t partnum;
  127. widgetreg_t widget_id;
  128. if (!xbow_widget_active(wid))
  129. return;
  130. widget_id = xtalk_read((void *)(IP30_RAW_SWIN_BASE(wid) + WIDGET_ID));
  131. partnum = XWIDGET_PART_NUM(widget_id);
  132. switch (partnum) {
  133. case BRIDGE_WIDGET_PART_NUM:
  134. case XBRIDGE_WIDGET_PART_NUM:
  135. bridge_platform_create(wid, masterwid);
  136. break;
  137. default:
  138. pr_info("xtalk:%x unknown widget (0x%x)\n", wid, partnum);
  139. break;
  140. }
  141. }
  142. static int __init ip30_xtalk_init(void)
  143. {
  144. int i;
  145. /*
  146. * Walk widget IDs backwards so that BaseIO is probed first. This
  147. * ensures that the BaseIO IOC3 is always detected as eth0.
  148. */
  149. for (i = IP30_WIDGET_PCI_BASE; i > IP30_WIDGET_HEART; i--)
  150. xtalk_init_widget(i, IP30_WIDGET_HEART);
  151. return 0;
  152. }
  153. arch_initcall(ip30_xtalk_init);