1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * ip30-xtalk.c - Very basic Crosstalk (XIO) detection support.
4*4882a593Smuzhiyun * Copyright (C) 2004-2007 Stanislaw Skowronek <skylark@unaligned.org>
5*4882a593Smuzhiyun * Copyright (C) 2009 Johannes Dickgreber <tanzy@gmx.de>
6*4882a593Smuzhiyun * Copyright (C) 2007, 2014-2016 Joshua Kinard <kumba@gentoo.org>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/init.h>
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/platform_device.h>
12*4882a593Smuzhiyun #include <linux/platform_data/sgi-w1.h>
13*4882a593Smuzhiyun #include <linux/platform_data/xtalk-bridge.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <asm/xtalk/xwidget.h>
16*4882a593Smuzhiyun #include <asm/pci/bridge.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define IP30_SWIN_BASE(widget) \
19*4882a593Smuzhiyun (0x0000000010000000 | (((unsigned long)(widget)) << 24))
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define IP30_RAW_SWIN_BASE(widget) (IO_BASE + IP30_SWIN_BASE(widget))
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define IP30_SWIN_SIZE (1 << 24)
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define IP30_WIDGET_XBOW _AC(0x0, UL) /* XBow is always 0 */
26*4882a593Smuzhiyun #define IP30_WIDGET_HEART _AC(0x8, UL) /* HEART is always 8 */
27*4882a593Smuzhiyun #define IP30_WIDGET_PCI_BASE _AC(0xf, UL) /* BaseIO PCI is always 15 */
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define XTALK_NODEV 0xffffffff
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define XBOW_REG_LINK_STAT_0 0x114
32*4882a593Smuzhiyun #define XBOW_REG_LINK_BLK_SIZE 0x40
33*4882a593Smuzhiyun #define XBOW_REG_LINK_ALIVE 0x80000000
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define HEART_INTR_ADDR 0x00000080
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define xtalk_read __raw_readl
38*4882a593Smuzhiyun
bridge_platform_create(int widget,int masterwid)39*4882a593Smuzhiyun static void bridge_platform_create(int widget, int masterwid)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun struct xtalk_bridge_platform_data *bd;
42*4882a593Smuzhiyun struct sgi_w1_platform_data *wd;
43*4882a593Smuzhiyun struct platform_device *pdev;
44*4882a593Smuzhiyun struct resource w1_res;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun wd = kzalloc(sizeof(*wd), GFP_KERNEL);
47*4882a593Smuzhiyun if (!wd)
48*4882a593Smuzhiyun goto no_mem;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
51*4882a593Smuzhiyun IP30_SWIN_BASE(widget));
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun memset(&w1_res, 0, sizeof(w1_res));
54*4882a593Smuzhiyun w1_res.start = IP30_SWIN_BASE(widget) +
55*4882a593Smuzhiyun offsetof(struct bridge_regs, b_nic);
56*4882a593Smuzhiyun w1_res.end = w1_res.start + 3;
57*4882a593Smuzhiyun w1_res.flags = IORESOURCE_MEM;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun pdev = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
60*4882a593Smuzhiyun if (!pdev) {
61*4882a593Smuzhiyun kfree(wd);
62*4882a593Smuzhiyun goto no_mem;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun platform_device_add_resources(pdev, &w1_res, 1);
65*4882a593Smuzhiyun platform_device_add_data(pdev, wd, sizeof(*wd));
66*4882a593Smuzhiyun platform_device_add(pdev);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun bd = kzalloc(sizeof(*bd), GFP_KERNEL);
69*4882a593Smuzhiyun if (!bd)
70*4882a593Smuzhiyun goto no_mem;
71*4882a593Smuzhiyun pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
72*4882a593Smuzhiyun if (!pdev) {
73*4882a593Smuzhiyun kfree(bd);
74*4882a593Smuzhiyun goto no_mem;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun bd->bridge_addr = IP30_RAW_SWIN_BASE(widget);
78*4882a593Smuzhiyun bd->intr_addr = HEART_INTR_ADDR;
79*4882a593Smuzhiyun bd->nasid = 0;
80*4882a593Smuzhiyun bd->masterwid = masterwid;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun bd->mem.name = "Bridge PCI MEM";
83*4882a593Smuzhiyun bd->mem.start = IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
84*4882a593Smuzhiyun bd->mem.end = IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
85*4882a593Smuzhiyun bd->mem.flags = IORESOURCE_MEM;
86*4882a593Smuzhiyun bd->mem_offset = IP30_SWIN_BASE(widget);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun bd->io.name = "Bridge PCI IO";
89*4882a593Smuzhiyun bd->io.start = IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
90*4882a593Smuzhiyun bd->io.end = IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
91*4882a593Smuzhiyun bd->io.flags = IORESOURCE_IO;
92*4882a593Smuzhiyun bd->io_offset = IP30_SWIN_BASE(widget);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun platform_device_add_data(pdev, bd, sizeof(*bd));
95*4882a593Smuzhiyun platform_device_add(pdev);
96*4882a593Smuzhiyun pr_info("xtalk:%x bridge widget\n", widget);
97*4882a593Smuzhiyun return;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun no_mem:
100*4882a593Smuzhiyun pr_warn("xtalk:%x bridge create out of memory\n", widget);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
xbow_widget_active(s8 wid)103*4882a593Smuzhiyun static unsigned int __init xbow_widget_active(s8 wid)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun unsigned int link_stat;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun link_stat = xtalk_read((void *)(IP30_RAW_SWIN_BASE(IP30_WIDGET_XBOW) +
108*4882a593Smuzhiyun XBOW_REG_LINK_STAT_0 +
109*4882a593Smuzhiyun XBOW_REG_LINK_BLK_SIZE *
110*4882a593Smuzhiyun (wid - 8)));
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun return (link_stat & XBOW_REG_LINK_ALIVE) ? 1 : 0;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
xtalk_init_widget(s8 wid,s8 masterwid)115*4882a593Smuzhiyun static void __init xtalk_init_widget(s8 wid, s8 masterwid)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun xwidget_part_num_t partnum;
118*4882a593Smuzhiyun widgetreg_t widget_id;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun if (!xbow_widget_active(wid))
121*4882a593Smuzhiyun return;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun widget_id = xtalk_read((void *)(IP30_RAW_SWIN_BASE(wid) + WIDGET_ID));
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun partnum = XWIDGET_PART_NUM(widget_id);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun switch (partnum) {
128*4882a593Smuzhiyun case BRIDGE_WIDGET_PART_NUM:
129*4882a593Smuzhiyun case XBRIDGE_WIDGET_PART_NUM:
130*4882a593Smuzhiyun bridge_platform_create(wid, masterwid);
131*4882a593Smuzhiyun break;
132*4882a593Smuzhiyun default:
133*4882a593Smuzhiyun pr_info("xtalk:%x unknown widget (0x%x)\n", wid, partnum);
134*4882a593Smuzhiyun break;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
ip30_xtalk_init(void)138*4882a593Smuzhiyun static int __init ip30_xtalk_init(void)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun int i;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /*
143*4882a593Smuzhiyun * Walk widget IDs backwards so that BaseIO is probed first. This
144*4882a593Smuzhiyun * ensures that the BaseIO IOC3 is always detected as eth0.
145*4882a593Smuzhiyun */
146*4882a593Smuzhiyun for (i = IP30_WIDGET_PCI_BASE; i > IP30_WIDGET_HEART; i--)
147*4882a593Smuzhiyun xtalk_init_widget(i, IP30_WIDGET_HEART);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun return 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun arch_initcall(ip30_xtalk_init);
153