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(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 | |
123 | err_put_pdev_bd: |
124 | platform_device_put(pdev: pdev_bd); |
125 | err_kfree_bd: |
126 | kfree(objp: bd); |
127 | err_unregister_pdev_wd: |
128 | platform_device_unregister(pdev_wd); |
129 | return; |
130 | err_put_pdev_wd: |
131 | platform_device_put(pdev: pdev_wd); |
132 | err_kfree_wd: |
133 | kfree(objp: 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(widget: 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(wid: i, IP30_WIDGET_HEART); |
182 | |
183 | return 0; |
184 | } |
185 | |
186 | arch_initcall(ip30_xtalk_init); |
187 | |