0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/init.h>
0010 #include <linux/kernel.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/platform_data/sgi-w1.h>
0013 #include <linux/platform_data/xtalk-bridge.h>
0014
0015 #include <asm/xtalk/xwidget.h>
0016 #include <asm/pci/bridge.h>
0017
0018 #define IP30_SWIN_BASE(widget) \
0019 (0x0000000010000000 | (((unsigned long)(widget)) << 24))
0020
0021 #define IP30_RAW_SWIN_BASE(widget) (IO_BASE + IP30_SWIN_BASE(widget))
0022
0023 #define IP30_SWIN_SIZE (1 << 24)
0024
0025 #define IP30_WIDGET_XBOW _AC(0x0, UL)
0026 #define IP30_WIDGET_HEART _AC(0x8, UL)
0027 #define IP30_WIDGET_PCI_BASE _AC(0xf, UL)
0028
0029 #define XTALK_NODEV 0xffffffff
0030
0031 #define XBOW_REG_LINK_STAT_0 0x114
0032 #define XBOW_REG_LINK_BLK_SIZE 0x40
0033 #define XBOW_REG_LINK_ALIVE 0x80000000
0034
0035 #define HEART_INTR_ADDR 0x00000080
0036
0037 #define xtalk_read __raw_readl
0038
0039 static void bridge_platform_create(int widget, int masterwid)
0040 {
0041 struct xtalk_bridge_platform_data *bd;
0042 struct sgi_w1_platform_data *wd;
0043 struct platform_device *pdev;
0044 struct resource w1_res;
0045
0046 wd = kzalloc(sizeof(*wd), GFP_KERNEL);
0047 if (!wd)
0048 goto no_mem;
0049
0050 snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
0051 IP30_SWIN_BASE(widget));
0052
0053 memset(&w1_res, 0, sizeof(w1_res));
0054 w1_res.start = IP30_SWIN_BASE(widget) +
0055 offsetof(struct bridge_regs, b_nic);
0056 w1_res.end = w1_res.start + 3;
0057 w1_res.flags = IORESOURCE_MEM;
0058
0059 pdev = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
0060 if (!pdev) {
0061 kfree(wd);
0062 goto no_mem;
0063 }
0064 platform_device_add_resources(pdev, &w1_res, 1);
0065 platform_device_add_data(pdev, wd, sizeof(*wd));
0066
0067 kfree(wd);
0068 platform_device_add(pdev);
0069
0070 bd = kzalloc(sizeof(*bd), GFP_KERNEL);
0071 if (!bd)
0072 goto no_mem;
0073 pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
0074 if (!pdev) {
0075 kfree(bd);
0076 goto no_mem;
0077 }
0078
0079 bd->bridge_addr = IP30_RAW_SWIN_BASE(widget);
0080 bd->intr_addr = HEART_INTR_ADDR;
0081 bd->nasid = 0;
0082 bd->masterwid = masterwid;
0083
0084 bd->mem.name = "Bridge PCI MEM";
0085 bd->mem.start = IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
0086 bd->mem.end = IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
0087 bd->mem.flags = IORESOURCE_MEM;
0088 bd->mem_offset = IP30_SWIN_BASE(widget);
0089
0090 bd->io.name = "Bridge PCI IO";
0091 bd->io.start = IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
0092 bd->io.end = IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
0093 bd->io.flags = IORESOURCE_IO;
0094 bd->io_offset = IP30_SWIN_BASE(widget);
0095
0096 platform_device_add_data(pdev, bd, sizeof(*bd));
0097
0098 kfree(bd);
0099 platform_device_add(pdev);
0100 pr_info("xtalk:%x bridge widget\n", widget);
0101 return;
0102
0103 no_mem:
0104 pr_warn("xtalk:%x bridge create out of memory\n", widget);
0105 }
0106
0107 static unsigned int __init xbow_widget_active(s8 wid)
0108 {
0109 unsigned int link_stat;
0110
0111 link_stat = xtalk_read((void *)(IP30_RAW_SWIN_BASE(IP30_WIDGET_XBOW) +
0112 XBOW_REG_LINK_STAT_0 +
0113 XBOW_REG_LINK_BLK_SIZE *
0114 (wid - 8)));
0115
0116 return (link_stat & XBOW_REG_LINK_ALIVE) ? 1 : 0;
0117 }
0118
0119 static void __init xtalk_init_widget(s8 wid, s8 masterwid)
0120 {
0121 xwidget_part_num_t partnum;
0122 widgetreg_t widget_id;
0123
0124 if (!xbow_widget_active(wid))
0125 return;
0126
0127 widget_id = xtalk_read((void *)(IP30_RAW_SWIN_BASE(wid) + WIDGET_ID));
0128
0129 partnum = XWIDGET_PART_NUM(widget_id);
0130
0131 switch (partnum) {
0132 case BRIDGE_WIDGET_PART_NUM:
0133 case XBRIDGE_WIDGET_PART_NUM:
0134 bridge_platform_create(wid, masterwid);
0135 break;
0136 default:
0137 pr_info("xtalk:%x unknown widget (0x%x)\n", wid, partnum);
0138 break;
0139 }
0140 }
0141
0142 static int __init ip30_xtalk_init(void)
0143 {
0144 int i;
0145
0146
0147
0148
0149
0150 for (i = IP30_WIDGET_PCI_BASE; i > IP30_WIDGET_HEART; i--)
0151 xtalk_init_widget(i, IP30_WIDGET_HEART);
0152
0153 return 0;
0154 }
0155
0156 arch_initcall(ip30_xtalk_init);