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