diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/sgi-ip27/ip27-xtalk.c | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/sgi-ip27/ip27-xtalk.c')
-rw-r--r-- | arch/mips/sgi-ip27/ip27-xtalk.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/arch/mips/sgi-ip27/ip27-xtalk.c b/arch/mips/sgi-ip27/ip27-xtalk.c new file mode 100644 index 000000000..5143d1cf8 --- /dev/null +++ b/arch/mips/sgi-ip27/ip27-xtalk.c | |||
@@ -0,0 +1,242 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org) | ||
4 | * Copyright (C) 1999, 2000 Silcon Graphics, Inc. | ||
5 | * Copyright (C) 2004 Christoph Hellwig. | ||
6 | * | ||
7 | * Generic XTALK initialization code | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/smp.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/platform_data/sgi-w1.h> | ||
14 | #include <linux/platform_data/xtalk-bridge.h> | ||
15 | #include <asm/sn/addrs.h> | ||
16 | #include <asm/sn/types.h> | ||
17 | #include <asm/sn/klconfig.h> | ||
18 | #include <asm/pci/bridge.h> | ||
19 | #include <asm/xtalk/xtalk.h> | ||
20 | |||
21 | |||
22 | #define XBOW_WIDGET_PART_NUM 0x0 | ||
23 | #define XXBOW_WIDGET_PART_NUM 0xd000 /* Xbow in Xbridge */ | ||
24 | #define BASE_XBOW_PORT 8 /* Lowest external port */ | ||
25 | |||
26 | static void bridge_platform_create(nasid_t nasid, int widget, int masterwid) | ||
27 | { | ||
28 | struct xtalk_bridge_platform_data *bd; | ||
29 | struct sgi_w1_platform_data *wd; | ||
30 | struct platform_device *pdev_wd; | ||
31 | struct platform_device *pdev_bd; | ||
32 | struct resource w1_res; | ||
33 | unsigned long offset; | ||
34 | |||
35 | offset = NODE_OFFSET(nasid); | ||
36 | |||
37 | wd = kzalloc(sizeof(*wd), GFP_KERNEL); | ||
38 | if (!wd) { | ||
39 | pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget); | ||
40 | return; | ||
41 | } | ||
42 | |||
43 | snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx", | ||
44 | offset + (widget << SWIN_SIZE_BITS)); | ||
45 | |||
46 | memset(&w1_res, 0, sizeof(w1_res)); | ||
47 | w1_res.start = offset + (widget << SWIN_SIZE_BITS) + | ||
48 | offsetof(struct bridge_regs, b_nic); | ||
49 | w1_res.end = w1_res.start + 3; | ||
50 | w1_res.flags = IORESOURCE_MEM; | ||
51 | |||
52 | pdev_wd = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO); | ||
53 | if (!pdev_wd) { | ||
54 | pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget); | ||
55 | goto err_kfree_wd; | ||
56 | } | ||
57 | if (platform_device_add_resources(pdev_wd, &w1_res, 1)) { | ||
58 | pr_warn("xtalk:n%d/%x bridge failed to add platform resources.\n", nasid, widget); | ||
59 | goto err_put_pdev_wd; | ||
60 | } | ||
61 | if (platform_device_add_data(pdev_wd, wd, sizeof(*wd))) { | ||
62 | pr_warn("xtalk:n%d/%x bridge failed to add platform data.\n", nasid, widget); | ||
63 | goto err_put_pdev_wd; | ||
64 | } | ||
65 | if (platform_device_add(pdev_wd)) { | ||
66 | pr_warn("xtalk:n%d/%x bridge failed to add platform device.\n", nasid, widget); | ||
67 | goto err_put_pdev_wd; | ||
68 | } | ||
69 | /* platform_device_add_data() duplicates the data */ | ||
70 | kfree(wd); | ||
71 | |||
72 | bd = kzalloc(sizeof(*bd), GFP_KERNEL); | ||
73 | if (!bd) { | ||
74 | pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget); | ||
75 | goto err_unregister_pdev_wd; | ||
76 | } | ||
77 | pdev_bd = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO); | ||
78 | if (!pdev_bd) { | ||
79 | pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget); | ||
80 | goto err_kfree_bd; | ||
81 | } | ||
82 | |||
83 | |||
84 | bd->bridge_addr = RAW_NODE_SWIN_BASE(nasid, widget); | ||
85 | bd->intr_addr = BIT_ULL(47) + 0x01800000 + PI_INT_PEND_MOD; | ||
86 | bd->nasid = nasid; | ||
87 | bd->masterwid = masterwid; | ||
88 | |||
89 | bd->mem.name = "Bridge PCI MEM"; | ||
90 | bd->mem.start = offset + (widget << SWIN_SIZE_BITS) + BRIDGE_DEVIO0; | ||
91 | bd->mem.end = offset + (widget << SWIN_SIZE_BITS) + SWIN_SIZE - 1; | ||
92 | bd->mem.flags = IORESOURCE_MEM; | ||
93 | bd->mem_offset = offset; | ||
94 | |||
95 | bd->io.name = "Bridge PCI IO"; | ||
96 | bd->io.start = offset + (widget << SWIN_SIZE_BITS) + BRIDGE_DEVIO0; | ||
97 | bd->io.end = offset + (widget << SWIN_SIZE_BITS) + SWIN_SIZE - 1; | ||
98 | bd->io.flags = IORESOURCE_IO; | ||
99 | bd->io_offset = offset; | ||
100 | |||
101 | if (platform_device_add_data(pdev_bd, bd, sizeof(*bd))) { | ||
102 | pr_warn("xtalk:n%d/%x bridge failed to add platform data.\n", nasid, widget); | ||
103 | goto err_put_pdev_bd; | ||
104 | } | ||
105 | if (platform_device_add(pdev_bd)) { | ||
106 | pr_warn("xtalk:n%d/%x bridge failed to add platform device.\n", nasid, widget); | ||
107 | goto err_put_pdev_bd; | ||
108 | } | ||
109 | /* platform_device_add_data() duplicates the data */ | ||
110 | kfree(bd); | ||
111 | pr_info("xtalk:n%d/%x bridge widget\n", nasid, widget); | ||
112 | return; | ||
113 | |||
114 | err_put_pdev_bd: | ||
115 | platform_device_put(pdev_bd); | ||
116 | err_kfree_bd: | ||
117 | kfree(bd); | ||
118 | err_unregister_pdev_wd: | ||
119 | platform_device_unregister(pdev_wd); | ||
120 | return; | ||
121 | err_put_pdev_wd: | ||
122 | platform_device_put(pdev_wd); | ||
123 | err_kfree_wd: | ||
124 | kfree(wd); | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | static int probe_one_port(nasid_t nasid, int widget, int masterwid) | ||
129 | { | ||
130 | widgetreg_t widget_id; | ||
131 | xwidget_part_num_t partnum; | ||
132 | |||
133 | widget_id = *(volatile widgetreg_t *) | ||
134 | (RAW_NODE_SWIN_BASE(nasid, widget) + WIDGET_ID); | ||
135 | partnum = XWIDGET_PART_NUM(widget_id); | ||
136 | |||
137 | switch (partnum) { | ||
138 | case BRIDGE_WIDGET_PART_NUM: | ||
139 | case XBRIDGE_WIDGET_PART_NUM: | ||
140 | bridge_platform_create(nasid, widget, masterwid); | ||
141 | break; | ||
142 | default: | ||
143 | pr_info("xtalk:n%d/%d unknown widget (0x%x)\n", | ||
144 | nasid, widget, partnum); | ||
145 | break; | ||
146 | } | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int xbow_probe(nasid_t nasid) | ||
152 | { | ||
153 | lboard_t *brd; | ||
154 | klxbow_t *xbow_p; | ||
155 | unsigned masterwid, i; | ||
156 | |||
157 | /* | ||
158 | * found xbow, so may have multiple bridges | ||
159 | * need to probe xbow | ||
160 | */ | ||
161 | brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8); | ||
162 | if (!brd) | ||
163 | return -ENODEV; | ||
164 | |||
165 | xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW); | ||
166 | if (!xbow_p) | ||
167 | return -ENODEV; | ||
168 | |||
169 | /* | ||
170 | * Okay, here's a xbow. Let's arbitrate and find | ||
171 | * out if we should initialize it. Set enabled | ||
172 | * hub connected at highest or lowest widget as | ||
173 | * master. | ||
174 | */ | ||
175 | #ifdef WIDGET_A | ||
176 | i = HUB_WIDGET_ID_MAX + 1; | ||
177 | do { | ||
178 | i--; | ||
179 | } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) || | ||
180 | (!XBOW_PORT_IS_ENABLED(xbow_p, i))); | ||
181 | #else | ||
182 | i = HUB_WIDGET_ID_MIN - 1; | ||
183 | do { | ||
184 | i++; | ||
185 | } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) || | ||
186 | (!XBOW_PORT_IS_ENABLED(xbow_p, i))); | ||
187 | #endif | ||
188 | |||
189 | masterwid = i; | ||
190 | if (nasid != XBOW_PORT_NASID(xbow_p, i)) | ||
191 | return 1; | ||
192 | |||
193 | for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) { | ||
194 | if (XBOW_PORT_IS_ENABLED(xbow_p, i) && | ||
195 | XBOW_PORT_TYPE_IO(xbow_p, i)) | ||
196 | probe_one_port(nasid, i, masterwid); | ||
197 | } | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static void xtalk_probe_node(nasid_t nasid) | ||
203 | { | ||
204 | volatile u64 hubreg; | ||
205 | xwidget_part_num_t partnum; | ||
206 | widgetreg_t widget_id; | ||
207 | |||
208 | hubreg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); | ||
209 | |||
210 | /* check whether the link is up */ | ||
211 | if (!(hubreg & IIO_LLP_CSR_IS_UP)) | ||
212 | return; | ||
213 | |||
214 | widget_id = *(volatile widgetreg_t *) | ||
215 | (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); | ||
216 | partnum = XWIDGET_PART_NUM(widget_id); | ||
217 | |||
218 | switch (partnum) { | ||
219 | case BRIDGE_WIDGET_PART_NUM: | ||
220 | bridge_platform_create(nasid, 0x8, 0xa); | ||
221 | break; | ||
222 | case XBOW_WIDGET_PART_NUM: | ||
223 | case XXBOW_WIDGET_PART_NUM: | ||
224 | pr_info("xtalk:n%d/0 xbow widget\n", nasid); | ||
225 | xbow_probe(nasid); | ||
226 | break; | ||
227 | default: | ||
228 | pr_info("xtalk:n%d/0 unknown widget (0x%x)\n", nasid, partnum); | ||
229 | break; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | static int __init xtalk_init(void) | ||
234 | { | ||
235 | nasid_t nasid; | ||
236 | |||
237 | for_each_online_node(nasid) | ||
238 | xtalk_probe_node(nasid); | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | arch_initcall(xtalk_init); | ||