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
bridge_platform_create(int widget,int masterwid)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;
44 struct resource w1_res;
45
46 wd = kzalloc(sizeof(*wd), GFP_KERNEL);
47 if (!wd)
48 goto no_mem;
49
50 snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
51 IP30_SWIN_BASE(widget));
52
53 memset(&w1_res, 0, sizeof(w1_res));
54 w1_res.start = IP30_SWIN_BASE(widget) +
55 offsetof(struct bridge_regs, b_nic);
56 w1_res.end = w1_res.start + 3;
57 w1_res.flags = IORESOURCE_MEM;
58
59 pdev = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
60 if (!pdev) {
61 kfree(wd);
62 goto no_mem;
63 }
64 platform_device_add_resources(pdev, &w1_res, 1);
65 platform_device_add_data(pdev, wd, sizeof(*wd));
66 platform_device_add(pdev);
67
68 bd = kzalloc(sizeof(*bd), GFP_KERNEL);
69 if (!bd)
70 goto no_mem;
71 pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
72 if (!pdev) {
73 kfree(bd);
74 goto no_mem;
75 }
76
77 bd->bridge_addr = IP30_RAW_SWIN_BASE(widget);
78 bd->intr_addr = HEART_INTR_ADDR;
79 bd->nasid = 0;
80 bd->masterwid = masterwid;
81
82 bd->mem.name = "Bridge PCI MEM";
83 bd->mem.start = IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
84 bd->mem.end = IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
85 bd->mem.flags = IORESOURCE_MEM;
86 bd->mem_offset = IP30_SWIN_BASE(widget);
87
88 bd->io.name = "Bridge PCI IO";
89 bd->io.start = IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
90 bd->io.end = IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
91 bd->io.flags = IORESOURCE_IO;
92 bd->io_offset = IP30_SWIN_BASE(widget);
93
94 platform_device_add_data(pdev, bd, sizeof(*bd));
95 platform_device_add(pdev);
96 pr_info("xtalk:%x bridge widget\n", widget);
97 return;
98
99 no_mem:
100 pr_warn("xtalk:%x bridge create out of memory\n", widget);
101 }
102
xbow_widget_active(s8 wid)103 static unsigned int __init xbow_widget_active(s8 wid)
104 {
105 unsigned int link_stat;
106
107 link_stat = xtalk_read((void *)(IP30_RAW_SWIN_BASE(IP30_WIDGET_XBOW) +
108 XBOW_REG_LINK_STAT_0 +
109 XBOW_REG_LINK_BLK_SIZE *
110 (wid - 8)));
111
112 return (link_stat & XBOW_REG_LINK_ALIVE) ? 1 : 0;
113 }
114
xtalk_init_widget(s8 wid,s8 masterwid)115 static void __init xtalk_init_widget(s8 wid, s8 masterwid)
116 {
117 xwidget_part_num_t partnum;
118 widgetreg_t widget_id;
119
120 if (!xbow_widget_active(wid))
121 return;
122
123 widget_id = xtalk_read((void *)(IP30_RAW_SWIN_BASE(wid) + WIDGET_ID));
124
125 partnum = XWIDGET_PART_NUM(widget_id);
126
127 switch (partnum) {
128 case BRIDGE_WIDGET_PART_NUM:
129 case XBRIDGE_WIDGET_PART_NUM:
130 bridge_platform_create(wid, masterwid);
131 break;
132 default:
133 pr_info("xtalk:%x unknown widget (0x%x)\n", wid, partnum);
134 break;
135 }
136 }
137
ip30_xtalk_init(void)138 static int __init ip30_xtalk_init(void)
139 {
140 int i;
141
142 /*
143 * Walk widget IDs backwards so that BaseIO is probed first. This
144 * ensures that the BaseIO IOC3 is always detected as eth0.
145 */
146 for (i = IP30_WIDGET_PCI_BASE; i > IP30_WIDGET_HEART; i--)
147 xtalk_init_widget(i, IP30_WIDGET_HEART);
148
149 return 0;
150 }
151
152 arch_initcall(ip30_xtalk_init);
153