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