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
39static 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(size: 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(buf: wd->dev_id, size: sizeof(wd->dev_id), fmt: "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(name: "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: pdev_wd, res: &w1_res, num: 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: pdev_wd, data: wd, size: 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: 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(objp: wd);
81
82 bd = kzalloc(size: 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(name: "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: pdev_bd, data: bd, size: 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: 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(objp: bd);
120 pr_info("xtalk:%x bridge widget\n", widget);
121 return;
122
123err_put_pdev_bd:
124 platform_device_put(pdev: pdev_bd);
125err_kfree_bd:
126 kfree(objp: bd);
127err_unregister_pdev_wd:
128 platform_device_unregister(pdev_wd);
129 return;
130err_put_pdev_wd:
131 platform_device_put(pdev: pdev_wd);
132err_kfree_wd:
133 kfree(objp: wd);
134 return;
135}
136
137static 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
149static 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(widget: wid, masterwid);
165 break;
166 default:
167 pr_info("xtalk:%x unknown widget (0x%x)\n", wid, partnum);
168 break;
169 }
170}
171
172static 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(wid: i, IP30_WIDGET_HEART);
182
183 return 0;
184}
185
186arch_initcall(ip30_xtalk_init);
187

source code of linux/arch/mips/sgi-ip30/ip30-xtalk.c