File Index
Files and directories
Sign in
FILE

ip30-xtalk.c

File preview with syntax highlighting.

linux-6.19.14/arch/mips/sgi-ip30/ip30-xtalk.c C
  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 <linux@kumba.dev>
  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(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
123err_put_pdev_bd:
124	platform_device_put(pdev_bd);
125err_kfree_bd:
126	kfree(bd);
127err_unregister_pdev_wd:
128	platform_device_unregister(pdev_wd);
129	return;
130err_put_pdev_wd:
131	platform_device_put(pdev_wd);
132err_kfree_wd:
133	kfree(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(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(i, IP30_WIDGET_HEART);
182
183	return 0;
184}
185
186arch_initcall(ip30_xtalk_init);
~/ Read-only file preview.