Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/sgi-ip30/ip30-xtalk.c
26424 views
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
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
188