xref: /openbmc/linux/arch/mips/sgi-ip30/ip30-xtalk.c (revision 399e7aa8)
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;
44 	struct resource w1_res;
45 
46 	wd = kzalloc(sizeof(*wd), GFP_KERNEL);
47 	if (!wd)
48 		goto no_mem;
49 
50 	snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
51 		 IP30_SWIN_BASE(widget));
52 
53 	memset(&w1_res, 0, sizeof(w1_res));
54 	w1_res.start = IP30_SWIN_BASE(widget) +
55 				offsetof(struct bridge_regs, b_nic);
56 	w1_res.end = w1_res.start + 3;
57 	w1_res.flags = IORESOURCE_MEM;
58 
59 	pdev = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
60 	if (!pdev) {
61 		kfree(wd);
62 		goto no_mem;
63 	}
64 	platform_device_add_resources(pdev, &w1_res, 1);
65 	platform_device_add_data(pdev, wd, sizeof(*wd));
66 	/* platform_device_add_data() duplicates the data */
67 	kfree(wd);
68 	platform_device_add(pdev);
69 
70 	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
71 	if (!bd)
72 		goto no_mem;
73 	pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
74 	if (!pdev) {
75 		kfree(bd);
76 		goto no_mem;
77 	}
78 
79 	bd->bridge_addr	= IP30_RAW_SWIN_BASE(widget);
80 	bd->intr_addr	= HEART_INTR_ADDR;
81 	bd->nasid	= 0;
82 	bd->masterwid	= masterwid;
83 
84 	bd->mem.name	= "Bridge PCI MEM";
85 	bd->mem.start	= IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
86 	bd->mem.end	= IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
87 	bd->mem.flags	= IORESOURCE_MEM;
88 	bd->mem_offset	= IP30_SWIN_BASE(widget);
89 
90 	bd->io.name	= "Bridge PCI IO";
91 	bd->io.start	= IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
92 	bd->io.end	= IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
93 	bd->io.flags	= IORESOURCE_IO;
94 	bd->io_offset	= IP30_SWIN_BASE(widget);
95 
96 	platform_device_add_data(pdev, bd, sizeof(*bd));
97 	/* platform_device_add_data() duplicates the data */
98 	kfree(bd);
99 	platform_device_add(pdev);
100 	pr_info("xtalk:%x bridge widget\n", widget);
101 	return;
102 
103 no_mem:
104 	pr_warn("xtalk:%x bridge create out of memory\n", widget);
105 }
106 
107 static unsigned int __init xbow_widget_active(s8 wid)
108 {
109 	unsigned int link_stat;
110 
111 	link_stat = xtalk_read((void *)(IP30_RAW_SWIN_BASE(IP30_WIDGET_XBOW) +
112 					XBOW_REG_LINK_STAT_0 +
113 					XBOW_REG_LINK_BLK_SIZE *
114 					(wid - 8)));
115 
116 	return (link_stat & XBOW_REG_LINK_ALIVE) ? 1 : 0;
117 }
118 
119 static void __init xtalk_init_widget(s8 wid, s8 masterwid)
120 {
121 	xwidget_part_num_t partnum;
122 	widgetreg_t widget_id;
123 
124 	if (!xbow_widget_active(wid))
125 		return;
126 
127 	widget_id = xtalk_read((void *)(IP30_RAW_SWIN_BASE(wid) + WIDGET_ID));
128 
129 	partnum = XWIDGET_PART_NUM(widget_id);
130 
131 	switch (partnum) {
132 	case BRIDGE_WIDGET_PART_NUM:
133 	case XBRIDGE_WIDGET_PART_NUM:
134 		bridge_platform_create(wid, masterwid);
135 		break;
136 	default:
137 		pr_info("xtalk:%x unknown widget (0x%x)\n", wid, partnum);
138 		break;
139 	}
140 }
141 
142 static int __init ip30_xtalk_init(void)
143 {
144 	int i;
145 
146 	/*
147 	 * Walk widget IDs backwards so that BaseIO is probed first.  This
148 	 * ensures that the BaseIO IOC3 is always detected as eth0.
149 	 */
150 	for (i = IP30_WIDGET_PCI_BASE; i > IP30_WIDGET_HEART; i--)
151 		xtalk_init_widget(i, IP30_WIDGET_HEART);
152 
153 	return 0;
154 }
155 
156 arch_initcall(ip30_xtalk_init);
157