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