arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / arch / mips / sgi-ip30 / ip30-xtalk.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 <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(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
123 err_put_pdev_bd:
124         platform_device_put(pdev_bd);
125 err_kfree_bd:
126         kfree(bd);
127 err_unregister_pdev_wd:
128         platform_device_unregister(pdev_wd);
129         return;
130 err_put_pdev_wd:
131         platform_device_put(pdev_wd);
132 err_kfree_wd:
133         kfree(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(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(i, IP30_WIDGET_HEART);
182
183         return 0;
184 }
185
186 arch_initcall(ip30_xtalk_init);