Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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);