Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * ip30-xtalk.c - Very basic Crosstalk (XIO) detection support.
0004  *   Copyright (C) 2004-2007 Stanislaw Skowronek <skylark@unaligned.org>
0005  *   Copyright (C) 2009 Johannes Dickgreber <tanzy@gmx.de>
0006  *   Copyright (C) 2007, 2014-2016 Joshua Kinard <kumba@gentoo.org>
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)    /* XBow is always 0 */
0026 #define IP30_WIDGET_HEART       _AC(0x8, UL)    /* HEART is always 8 */
0027 #define IP30_WIDGET_PCI_BASE    _AC(0xf, UL)    /* BaseIO PCI is always 15 */
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     /* platform_device_add_data() duplicates the data */
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     /* platform_device_add_data() duplicates the data */
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      * Walk widget IDs backwards so that BaseIO is probed first.  This
0148      * ensures that the BaseIO IOC3 is always detected as eth0.
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);