xref: /openbmc/linux/arch/mips/pci/pci-xtalk-bridge.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1a57140e9SThomas Bogendoerfer // SPDX-License-Identifier: GPL-2.0
2a57140e9SThomas Bogendoerfer /*
3a57140e9SThomas Bogendoerfer  * Copyright (C) 2003 Christoph Hellwig (hch@lst.de)
4a57140e9SThomas Bogendoerfer  * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
5a57140e9SThomas Bogendoerfer  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
6a57140e9SThomas Bogendoerfer  */
7a57140e9SThomas Bogendoerfer #include <linux/kernel.h>
8a57140e9SThomas Bogendoerfer #include <linux/export.h>
9a57140e9SThomas Bogendoerfer #include <linux/pci.h>
10a57140e9SThomas Bogendoerfer #include <linux/smp.h>
11a57140e9SThomas Bogendoerfer #include <linux/dma-direct.h>
12a57140e9SThomas Bogendoerfer #include <linux/platform_device.h>
13a57140e9SThomas Bogendoerfer #include <linux/platform_data/xtalk-bridge.h>
145dc76a96SThomas Bogendoerfer #include <linux/nvmem-consumer.h>
155dc76a96SThomas Bogendoerfer #include <linux/crc16.h>
1618ca45f5SMarc Zyngier #include <linux/irqdomain.h>
17a57140e9SThomas Bogendoerfer 
18a57140e9SThomas Bogendoerfer #include <asm/pci/bridge.h>
19a57140e9SThomas Bogendoerfer #include <asm/paccess.h>
20e6308b6dSThomas Bogendoerfer #include <asm/sn/irq_alloc.h>
215dc76a96SThomas Bogendoerfer #include <asm/sn/ioc3.h>
225dc76a96SThomas Bogendoerfer 
235dc76a96SThomas Bogendoerfer #define CRC16_INIT	0
245dc76a96SThomas Bogendoerfer #define CRC16_VALID	0xb001
25a57140e9SThomas Bogendoerfer 
26a57140e9SThomas Bogendoerfer /*
27b9e9defbSThomas Bogendoerfer  * Common phys<->dma mapping for platforms using pci xtalk bridge
28b9e9defbSThomas Bogendoerfer  */
phys_to_dma(struct device * dev,phys_addr_t paddr)295ceda740SChristoph Hellwig dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
30b9e9defbSThomas Bogendoerfer {
31b9e9defbSThomas Bogendoerfer 	struct pci_dev *pdev = to_pci_dev(dev);
32b9e9defbSThomas Bogendoerfer 	struct bridge_controller *bc = BRIDGE_CONTROLLER(pdev->bus);
33b9e9defbSThomas Bogendoerfer 
34b9e9defbSThomas Bogendoerfer 	return bc->baddr + paddr;
35b9e9defbSThomas Bogendoerfer }
36b9e9defbSThomas Bogendoerfer 
dma_to_phys(struct device * dev,dma_addr_t dma_addr)377bc5c428SChristoph Hellwig phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dma_addr)
38b9e9defbSThomas Bogendoerfer {
39b9e9defbSThomas Bogendoerfer 	return dma_addr & ~(0xffUL << 56);
40b9e9defbSThomas Bogendoerfer }
41b9e9defbSThomas Bogendoerfer 
42b9e9defbSThomas Bogendoerfer /*
43a57140e9SThomas Bogendoerfer  * Most of the IOC3 PCI config register aren't present
44a57140e9SThomas Bogendoerfer  * we emulate what is needed for a normal PCI enumeration
45a57140e9SThomas Bogendoerfer  */
ioc3_cfg_rd(void * addr,int where,int size,u32 * value,u32 sid)465dc76a96SThomas Bogendoerfer static int ioc3_cfg_rd(void *addr, int where, int size, u32 *value, u32 sid)
47a57140e9SThomas Bogendoerfer {
48813cafc4SThomas Bogendoerfer 	u32 cf, shift, mask;
49a57140e9SThomas Bogendoerfer 
50813cafc4SThomas Bogendoerfer 	switch (where & ~3) {
51813cafc4SThomas Bogendoerfer 	case 0x00 ... 0x10:
52813cafc4SThomas Bogendoerfer 	case 0x40 ... 0x44:
53813cafc4SThomas Bogendoerfer 		if (get_dbe(cf, (u32 *)addr))
54813cafc4SThomas Bogendoerfer 			return PCIBIOS_DEVICE_NOT_FOUND;
55813cafc4SThomas Bogendoerfer 		break;
565dc76a96SThomas Bogendoerfer 	case 0x2c:
575dc76a96SThomas Bogendoerfer 		cf = sid;
585dc76a96SThomas Bogendoerfer 		break;
59813cafc4SThomas Bogendoerfer 	case 0x3c:
60813cafc4SThomas Bogendoerfer 		/* emulate sane interrupt pin value */
61813cafc4SThomas Bogendoerfer 		cf = 0x00000100;
62813cafc4SThomas Bogendoerfer 		break;
63813cafc4SThomas Bogendoerfer 	default:
64813cafc4SThomas Bogendoerfer 		cf = 0;
65813cafc4SThomas Bogendoerfer 		break;
66813cafc4SThomas Bogendoerfer 	}
67813cafc4SThomas Bogendoerfer 	shift = (where & 3) << 3;
68813cafc4SThomas Bogendoerfer 	mask = 0xffffffffU >> ((4 - size) << 3);
69813cafc4SThomas Bogendoerfer 	*value = (cf >> shift) & mask;
70813cafc4SThomas Bogendoerfer 
71813cafc4SThomas Bogendoerfer 	return PCIBIOS_SUCCESSFUL;
72813cafc4SThomas Bogendoerfer }
73813cafc4SThomas Bogendoerfer 
ioc3_cfg_wr(void * addr,int where,int size,u32 value)74813cafc4SThomas Bogendoerfer static int ioc3_cfg_wr(void *addr, int where, int size, u32 value)
75813cafc4SThomas Bogendoerfer {
76813cafc4SThomas Bogendoerfer 	u32 cf, shift, mask, smask;
77813cafc4SThomas Bogendoerfer 
78813cafc4SThomas Bogendoerfer 	if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
79813cafc4SThomas Bogendoerfer 		return PCIBIOS_SUCCESSFUL;
80813cafc4SThomas Bogendoerfer 
81813cafc4SThomas Bogendoerfer 	if (get_dbe(cf, (u32 *)addr))
82813cafc4SThomas Bogendoerfer 		return PCIBIOS_DEVICE_NOT_FOUND;
83813cafc4SThomas Bogendoerfer 
84813cafc4SThomas Bogendoerfer 	shift = ((where & 3) << 3);
85813cafc4SThomas Bogendoerfer 	mask = (0xffffffffU >> ((4 - size) << 3));
86813cafc4SThomas Bogendoerfer 	smask = mask << shift;
87813cafc4SThomas Bogendoerfer 
88813cafc4SThomas Bogendoerfer 	cf = (cf & ~smask) | ((value & mask) << shift);
89813cafc4SThomas Bogendoerfer 	if (put_dbe(cf, (u32 *)addr))
90813cafc4SThomas Bogendoerfer 		return PCIBIOS_DEVICE_NOT_FOUND;
91813cafc4SThomas Bogendoerfer 
92813cafc4SThomas Bogendoerfer 	return PCIBIOS_SUCCESSFUL;
93a57140e9SThomas Bogendoerfer }
94a57140e9SThomas Bogendoerfer 
bridge_disable_swapping(struct pci_dev * dev)95a57140e9SThomas Bogendoerfer static void bridge_disable_swapping(struct pci_dev *dev)
96a57140e9SThomas Bogendoerfer {
97a57140e9SThomas Bogendoerfer 	struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
98a57140e9SThomas Bogendoerfer 	int slot = PCI_SLOT(dev->devfn);
99a57140e9SThomas Bogendoerfer 
100a57140e9SThomas Bogendoerfer 	/* Turn off byte swapping */
101a57140e9SThomas Bogendoerfer 	bridge_clr(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
102a57140e9SThomas Bogendoerfer 	bridge_read(bc, b_widget.w_tflush);	/* Flush */
103a57140e9SThomas Bogendoerfer }
104a57140e9SThomas Bogendoerfer 
105a57140e9SThomas Bogendoerfer DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
106a57140e9SThomas Bogendoerfer 	bridge_disable_swapping);
107a57140e9SThomas Bogendoerfer 
108a57140e9SThomas Bogendoerfer 
109a57140e9SThomas Bogendoerfer /*
110a57140e9SThomas Bogendoerfer  * The Bridge ASIC supports both type 0 and type 1 access.  Type 1 is
111a57140e9SThomas Bogendoerfer  * not really documented, so right now I can't write code which uses it.
112a57140e9SThomas Bogendoerfer  * Therefore we use type 0 accesses for now even though they won't work
113a57140e9SThomas Bogendoerfer  * correctly for PCI-to-PCI bridges.
114a57140e9SThomas Bogendoerfer  *
115a57140e9SThomas Bogendoerfer  * The function is complicated by the ultimate brokenness of the IOC3 chip
116a57140e9SThomas Bogendoerfer  * which is used in SGI systems.  The IOC3 can only handle 32-bit PCI
117a57140e9SThomas Bogendoerfer  * accesses and does only decode parts of it's address space.
118a57140e9SThomas Bogendoerfer  */
pci_conf0_read_config(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 * value)119a57140e9SThomas Bogendoerfer static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
120a57140e9SThomas Bogendoerfer 				 int where, int size, u32 *value)
121a57140e9SThomas Bogendoerfer {
122a57140e9SThomas Bogendoerfer 	struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
123a57140e9SThomas Bogendoerfer 	struct bridge_regs *bridge = bc->base;
124a57140e9SThomas Bogendoerfer 	int slot = PCI_SLOT(devfn);
125a57140e9SThomas Bogendoerfer 	int fn = PCI_FUNC(devfn);
126a57140e9SThomas Bogendoerfer 	void *addr;
127813cafc4SThomas Bogendoerfer 	u32 cf;
128a57140e9SThomas Bogendoerfer 	int res;
129a57140e9SThomas Bogendoerfer 
130a57140e9SThomas Bogendoerfer 	addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
131a57140e9SThomas Bogendoerfer 	if (get_dbe(cf, (u32 *)addr))
132a57140e9SThomas Bogendoerfer 		return PCIBIOS_DEVICE_NOT_FOUND;
133a57140e9SThomas Bogendoerfer 
134a57140e9SThomas Bogendoerfer 	/*
135a57140e9SThomas Bogendoerfer 	 * IOC3 is broken beyond belief ...  Don't even give the
136a57140e9SThomas Bogendoerfer 	 * generic PCI code a chance to look at it for real ...
137a57140e9SThomas Bogendoerfer 	 */
138813cafc4SThomas Bogendoerfer 	if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) {
139813cafc4SThomas Bogendoerfer 		addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
1405dc76a96SThomas Bogendoerfer 		return ioc3_cfg_rd(addr, where, size, value,
1415dc76a96SThomas Bogendoerfer 				   bc->ioc3_sid[slot]);
142813cafc4SThomas Bogendoerfer 	}
143a57140e9SThomas Bogendoerfer 
144a57140e9SThomas Bogendoerfer 	addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
145a57140e9SThomas Bogendoerfer 
146a57140e9SThomas Bogendoerfer 	if (size == 1)
147a57140e9SThomas Bogendoerfer 		res = get_dbe(*value, (u8 *)addr);
148a57140e9SThomas Bogendoerfer 	else if (size == 2)
149a57140e9SThomas Bogendoerfer 		res = get_dbe(*value, (u16 *)addr);
150a57140e9SThomas Bogendoerfer 	else
151a57140e9SThomas Bogendoerfer 		res = get_dbe(*value, (u32 *)addr);
152a57140e9SThomas Bogendoerfer 
153a57140e9SThomas Bogendoerfer 	return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
154a57140e9SThomas Bogendoerfer }
155a57140e9SThomas Bogendoerfer 
pci_conf1_read_config(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 * value)156a57140e9SThomas Bogendoerfer static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
157a57140e9SThomas Bogendoerfer 				 int where, int size, u32 *value)
158a57140e9SThomas Bogendoerfer {
159a57140e9SThomas Bogendoerfer 	struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
160a57140e9SThomas Bogendoerfer 	struct bridge_regs *bridge = bc->base;
161a57140e9SThomas Bogendoerfer 	int busno = bus->number;
162a57140e9SThomas Bogendoerfer 	int slot = PCI_SLOT(devfn);
163a57140e9SThomas Bogendoerfer 	int fn = PCI_FUNC(devfn);
164a57140e9SThomas Bogendoerfer 	void *addr;
165813cafc4SThomas Bogendoerfer 	u32 cf;
166a57140e9SThomas Bogendoerfer 	int res;
167a57140e9SThomas Bogendoerfer 
168a57140e9SThomas Bogendoerfer 	bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
169a57140e9SThomas Bogendoerfer 	addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
170a57140e9SThomas Bogendoerfer 	if (get_dbe(cf, (u32 *)addr))
171a57140e9SThomas Bogendoerfer 		return PCIBIOS_DEVICE_NOT_FOUND;
172a57140e9SThomas Bogendoerfer 
173a57140e9SThomas Bogendoerfer 	/*
174a57140e9SThomas Bogendoerfer 	 * IOC3 is broken beyond belief ...  Don't even give the
175a57140e9SThomas Bogendoerfer 	 * generic PCI code a chance to look at it for real ...
176a57140e9SThomas Bogendoerfer 	 */
177813cafc4SThomas Bogendoerfer 	if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) {
178813cafc4SThomas Bogendoerfer 		addr = &bridge->b_type1_cfg.c[(fn << 8) | (where & ~3)];
1795dc76a96SThomas Bogendoerfer 		return ioc3_cfg_rd(addr, where, size, value,
1805dc76a96SThomas Bogendoerfer 				   bc->ioc3_sid[slot]);
181813cafc4SThomas Bogendoerfer 	}
182a57140e9SThomas Bogendoerfer 
183a57140e9SThomas Bogendoerfer 	addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
184a57140e9SThomas Bogendoerfer 
185a57140e9SThomas Bogendoerfer 	if (size == 1)
186a57140e9SThomas Bogendoerfer 		res = get_dbe(*value, (u8 *)addr);
187a57140e9SThomas Bogendoerfer 	else if (size == 2)
188a57140e9SThomas Bogendoerfer 		res = get_dbe(*value, (u16 *)addr);
189a57140e9SThomas Bogendoerfer 	else
190a57140e9SThomas Bogendoerfer 		res = get_dbe(*value, (u32 *)addr);
191a57140e9SThomas Bogendoerfer 
192a57140e9SThomas Bogendoerfer 	return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
193a57140e9SThomas Bogendoerfer }
194a57140e9SThomas Bogendoerfer 
pci_read_config(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 * value)195a57140e9SThomas Bogendoerfer static int pci_read_config(struct pci_bus *bus, unsigned int devfn,
196a57140e9SThomas Bogendoerfer 			   int where, int size, u32 *value)
197a57140e9SThomas Bogendoerfer {
198a57140e9SThomas Bogendoerfer 	if (!pci_is_root_bus(bus))
199a57140e9SThomas Bogendoerfer 		return pci_conf1_read_config(bus, devfn, where, size, value);
200a57140e9SThomas Bogendoerfer 
201a57140e9SThomas Bogendoerfer 	return pci_conf0_read_config(bus, devfn, where, size, value);
202a57140e9SThomas Bogendoerfer }
203a57140e9SThomas Bogendoerfer 
pci_conf0_write_config(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 value)204a57140e9SThomas Bogendoerfer static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
205a57140e9SThomas Bogendoerfer 				  int where, int size, u32 value)
206a57140e9SThomas Bogendoerfer {
207a57140e9SThomas Bogendoerfer 	struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
208a57140e9SThomas Bogendoerfer 	struct bridge_regs *bridge = bc->base;
209a57140e9SThomas Bogendoerfer 	int slot = PCI_SLOT(devfn);
210a57140e9SThomas Bogendoerfer 	int fn = PCI_FUNC(devfn);
211a57140e9SThomas Bogendoerfer 	void *addr;
212813cafc4SThomas Bogendoerfer 	u32 cf;
213a57140e9SThomas Bogendoerfer 	int res;
214a57140e9SThomas Bogendoerfer 
215a57140e9SThomas Bogendoerfer 	addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
216a57140e9SThomas Bogendoerfer 	if (get_dbe(cf, (u32 *)addr))
217a57140e9SThomas Bogendoerfer 		return PCIBIOS_DEVICE_NOT_FOUND;
218a57140e9SThomas Bogendoerfer 
219a57140e9SThomas Bogendoerfer 	/*
220a57140e9SThomas Bogendoerfer 	 * IOC3 is broken beyond belief ...  Don't even give the
221a57140e9SThomas Bogendoerfer 	 * generic PCI code a chance to look at it for real ...
222a57140e9SThomas Bogendoerfer 	 */
223813cafc4SThomas Bogendoerfer 	if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) {
224813cafc4SThomas Bogendoerfer 		addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
225813cafc4SThomas Bogendoerfer 		return ioc3_cfg_wr(addr, where, size, value);
226813cafc4SThomas Bogendoerfer 	}
227a57140e9SThomas Bogendoerfer 
228a57140e9SThomas Bogendoerfer 	addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
229a57140e9SThomas Bogendoerfer 
230a57140e9SThomas Bogendoerfer 	if (size == 1)
231a57140e9SThomas Bogendoerfer 		res = put_dbe(value, (u8 *)addr);
232a57140e9SThomas Bogendoerfer 	else if (size == 2)
233a57140e9SThomas Bogendoerfer 		res = put_dbe(value, (u16 *)addr);
234a57140e9SThomas Bogendoerfer 	else
235a57140e9SThomas Bogendoerfer 		res = put_dbe(value, (u32 *)addr);
236a57140e9SThomas Bogendoerfer 
237a57140e9SThomas Bogendoerfer 	if (res)
238a57140e9SThomas Bogendoerfer 		return PCIBIOS_DEVICE_NOT_FOUND;
239a57140e9SThomas Bogendoerfer 
240a57140e9SThomas Bogendoerfer 	return PCIBIOS_SUCCESSFUL;
241a57140e9SThomas Bogendoerfer }
242a57140e9SThomas Bogendoerfer 
pci_conf1_write_config(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 value)243a57140e9SThomas Bogendoerfer static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
244a57140e9SThomas Bogendoerfer 				  int where, int size, u32 value)
245a57140e9SThomas Bogendoerfer {
246a57140e9SThomas Bogendoerfer 	struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
247a57140e9SThomas Bogendoerfer 	struct bridge_regs *bridge = bc->base;
248a57140e9SThomas Bogendoerfer 	int slot = PCI_SLOT(devfn);
249a57140e9SThomas Bogendoerfer 	int fn = PCI_FUNC(devfn);
250a57140e9SThomas Bogendoerfer 	int busno = bus->number;
251a57140e9SThomas Bogendoerfer 	void *addr;
252813cafc4SThomas Bogendoerfer 	u32 cf;
253a57140e9SThomas Bogendoerfer 	int res;
254a57140e9SThomas Bogendoerfer 
255a57140e9SThomas Bogendoerfer 	bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
256a57140e9SThomas Bogendoerfer 	addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
257a57140e9SThomas Bogendoerfer 	if (get_dbe(cf, (u32 *)addr))
258a57140e9SThomas Bogendoerfer 		return PCIBIOS_DEVICE_NOT_FOUND;
259a57140e9SThomas Bogendoerfer 
260a57140e9SThomas Bogendoerfer 	/*
261a57140e9SThomas Bogendoerfer 	 * IOC3 is broken beyond belief ...  Don't even give the
262a57140e9SThomas Bogendoerfer 	 * generic PCI code a chance to look at it for real ...
263a57140e9SThomas Bogendoerfer 	 */
264813cafc4SThomas Bogendoerfer 	if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) {
265813cafc4SThomas Bogendoerfer 		addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
266813cafc4SThomas Bogendoerfer 		return ioc3_cfg_wr(addr, where, size, value);
267813cafc4SThomas Bogendoerfer 	}
268a57140e9SThomas Bogendoerfer 
269a57140e9SThomas Bogendoerfer 	addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
270a57140e9SThomas Bogendoerfer 
271a57140e9SThomas Bogendoerfer 	if (size == 1)
272a57140e9SThomas Bogendoerfer 		res = put_dbe(value, (u8 *)addr);
273a57140e9SThomas Bogendoerfer 	else if (size == 2)
274a57140e9SThomas Bogendoerfer 		res = put_dbe(value, (u16 *)addr);
275a57140e9SThomas Bogendoerfer 	else
276a57140e9SThomas Bogendoerfer 		res = put_dbe(value, (u32 *)addr);
277a57140e9SThomas Bogendoerfer 
278a57140e9SThomas Bogendoerfer 	if (res)
279a57140e9SThomas Bogendoerfer 		return PCIBIOS_DEVICE_NOT_FOUND;
280a57140e9SThomas Bogendoerfer 
281a57140e9SThomas Bogendoerfer 	return PCIBIOS_SUCCESSFUL;
282a57140e9SThomas Bogendoerfer }
283a57140e9SThomas Bogendoerfer 
pci_write_config(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 value)284a57140e9SThomas Bogendoerfer static int pci_write_config(struct pci_bus *bus, unsigned int devfn,
285a57140e9SThomas Bogendoerfer 	int where, int size, u32 value)
286a57140e9SThomas Bogendoerfer {
287a57140e9SThomas Bogendoerfer 	if (!pci_is_root_bus(bus))
288a57140e9SThomas Bogendoerfer 		return pci_conf1_write_config(bus, devfn, where, size, value);
289a57140e9SThomas Bogendoerfer 
290a57140e9SThomas Bogendoerfer 	return pci_conf0_write_config(bus, devfn, where, size, value);
291a57140e9SThomas Bogendoerfer }
292a57140e9SThomas Bogendoerfer 
293a57140e9SThomas Bogendoerfer static struct pci_ops bridge_pci_ops = {
294a57140e9SThomas Bogendoerfer 	.read	 = pci_read_config,
295a57140e9SThomas Bogendoerfer 	.write	 = pci_write_config,
296a57140e9SThomas Bogendoerfer };
297a57140e9SThomas Bogendoerfer 
298e6308b6dSThomas Bogendoerfer struct bridge_irq_chip_data {
299e6308b6dSThomas Bogendoerfer 	struct bridge_controller *bc;
300e6308b6dSThomas Bogendoerfer 	nasid_t nasid;
301e6308b6dSThomas Bogendoerfer };
302e6308b6dSThomas Bogendoerfer 
bridge_set_affinity(struct irq_data * d,const struct cpumask * mask,bool force)303e6308b6dSThomas Bogendoerfer static int bridge_set_affinity(struct irq_data *d, const struct cpumask *mask,
304e6308b6dSThomas Bogendoerfer 			       bool force)
305e6308b6dSThomas Bogendoerfer {
306e6308b6dSThomas Bogendoerfer #ifdef CONFIG_NUMA
307e6308b6dSThomas Bogendoerfer 	struct bridge_irq_chip_data *data = d->chip_data;
308e6308b6dSThomas Bogendoerfer 	int bit = d->parent_data->hwirq;
309e6308b6dSThomas Bogendoerfer 	int pin = d->hwirq;
310e6308b6dSThomas Bogendoerfer 	int ret, cpu;
311e6308b6dSThomas Bogendoerfer 
312e6308b6dSThomas Bogendoerfer 	ret = irq_chip_set_affinity_parent(d, mask, force);
313e6308b6dSThomas Bogendoerfer 	if (ret >= 0) {
314e6308b6dSThomas Bogendoerfer 		cpu = cpumask_first_and(mask, cpu_online_mask);
31537640adbSThomas Bogendoerfer 		data->nasid = cpu_to_node(cpu);
316e6308b6dSThomas Bogendoerfer 		bridge_write(data->bc, b_int_addr[pin].addr,
317e6308b6dSThomas Bogendoerfer 			     (((data->bc->intr_addr >> 30) & 0x30000) |
31837640adbSThomas Bogendoerfer 			      bit | (data->nasid << 8)));
319e6308b6dSThomas Bogendoerfer 		bridge_read(data->bc, b_wid_tflush);
320e6308b6dSThomas Bogendoerfer 	}
321e6308b6dSThomas Bogendoerfer 	return ret;
322e6308b6dSThomas Bogendoerfer #else
323e6308b6dSThomas Bogendoerfer 	return irq_chip_set_affinity_parent(d, mask, force);
324e6308b6dSThomas Bogendoerfer #endif
325e6308b6dSThomas Bogendoerfer }
326e6308b6dSThomas Bogendoerfer 
327e6308b6dSThomas Bogendoerfer struct irq_chip bridge_irq_chip = {
328e6308b6dSThomas Bogendoerfer 	.name             = "BRIDGE",
329e6308b6dSThomas Bogendoerfer 	.irq_mask         = irq_chip_mask_parent,
330e6308b6dSThomas Bogendoerfer 	.irq_unmask       = irq_chip_unmask_parent,
331e6308b6dSThomas Bogendoerfer 	.irq_set_affinity = bridge_set_affinity
332e6308b6dSThomas Bogendoerfer };
333e6308b6dSThomas Bogendoerfer 
bridge_domain_alloc(struct irq_domain * domain,unsigned int virq,unsigned int nr_irqs,void * arg)334e6308b6dSThomas Bogendoerfer static int bridge_domain_alloc(struct irq_domain *domain, unsigned int virq,
335e6308b6dSThomas Bogendoerfer 			       unsigned int nr_irqs, void *arg)
336e6308b6dSThomas Bogendoerfer {
337e6308b6dSThomas Bogendoerfer 	struct bridge_irq_chip_data *data;
338e6308b6dSThomas Bogendoerfer 	struct irq_alloc_info *info = arg;
339e6308b6dSThomas Bogendoerfer 	int ret;
340e6308b6dSThomas Bogendoerfer 
341e6308b6dSThomas Bogendoerfer 	if (nr_irqs > 1 || !info)
342e6308b6dSThomas Bogendoerfer 		return -EINVAL;
343e6308b6dSThomas Bogendoerfer 
344e6308b6dSThomas Bogendoerfer 	data = kzalloc(sizeof(*data), GFP_KERNEL);
345e6308b6dSThomas Bogendoerfer 	if (!data)
346e6308b6dSThomas Bogendoerfer 		return -ENOMEM;
347e6308b6dSThomas Bogendoerfer 
348e6308b6dSThomas Bogendoerfer 	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
349e6308b6dSThomas Bogendoerfer 	if (ret >= 0) {
350e6308b6dSThomas Bogendoerfer 		data->bc = info->ctrl;
351e6308b6dSThomas Bogendoerfer 		data->nasid = info->nasid;
352e6308b6dSThomas Bogendoerfer 		irq_domain_set_info(domain, virq, info->pin, &bridge_irq_chip,
353e6308b6dSThomas Bogendoerfer 				    data, handle_level_irq, NULL, NULL);
354e6308b6dSThomas Bogendoerfer 	} else {
355e6308b6dSThomas Bogendoerfer 		kfree(data);
356e6308b6dSThomas Bogendoerfer 	}
357e6308b6dSThomas Bogendoerfer 
358e6308b6dSThomas Bogendoerfer 	return ret;
359e6308b6dSThomas Bogendoerfer }
360e6308b6dSThomas Bogendoerfer 
bridge_domain_free(struct irq_domain * domain,unsigned int virq,unsigned int nr_irqs)361e6308b6dSThomas Bogendoerfer static void bridge_domain_free(struct irq_domain *domain, unsigned int virq,
362e6308b6dSThomas Bogendoerfer 			       unsigned int nr_irqs)
363e6308b6dSThomas Bogendoerfer {
364e6308b6dSThomas Bogendoerfer 	struct irq_data *irqd = irq_domain_get_irq_data(domain, virq);
365e6308b6dSThomas Bogendoerfer 
366e6308b6dSThomas Bogendoerfer 	if (nr_irqs)
367e6308b6dSThomas Bogendoerfer 		return;
368e6308b6dSThomas Bogendoerfer 
369e6308b6dSThomas Bogendoerfer 	kfree(irqd->chip_data);
370e6308b6dSThomas Bogendoerfer 	irq_domain_free_irqs_top(domain, virq, nr_irqs);
371e6308b6dSThomas Bogendoerfer }
372e6308b6dSThomas Bogendoerfer 
bridge_domain_activate(struct irq_domain * domain,struct irq_data * irqd,bool reserve)373e6308b6dSThomas Bogendoerfer static int bridge_domain_activate(struct irq_domain *domain,
374e6308b6dSThomas Bogendoerfer 				  struct irq_data *irqd, bool reserve)
375e6308b6dSThomas Bogendoerfer {
376e6308b6dSThomas Bogendoerfer 	struct bridge_irq_chip_data *data = irqd->chip_data;
377e6308b6dSThomas Bogendoerfer 	struct bridge_controller *bc = data->bc;
378e6308b6dSThomas Bogendoerfer 	int bit = irqd->parent_data->hwirq;
379e6308b6dSThomas Bogendoerfer 	int pin = irqd->hwirq;
380e6308b6dSThomas Bogendoerfer 	u32 device;
381e6308b6dSThomas Bogendoerfer 
382e6308b6dSThomas Bogendoerfer 	bridge_write(bc, b_int_addr[pin].addr,
383e6308b6dSThomas Bogendoerfer 		     (((bc->intr_addr >> 30) & 0x30000) |
384e6308b6dSThomas Bogendoerfer 		      bit | (data->nasid << 8)));
385e6308b6dSThomas Bogendoerfer 	bridge_set(bc, b_int_enable, (1 << pin));
386e6308b6dSThomas Bogendoerfer 	bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
387e6308b6dSThomas Bogendoerfer 
388e6308b6dSThomas Bogendoerfer 	/*
3898455033cSBhaskar Chowdhury 	 * Enable sending of an interrupt clear packet to the hub on a high to
390e6308b6dSThomas Bogendoerfer 	 * low transition of the interrupt pin.
391e6308b6dSThomas Bogendoerfer 	 *
392e6308b6dSThomas Bogendoerfer 	 * IRIX sets additional bits in the address which are documented as
393e6308b6dSThomas Bogendoerfer 	 * reserved in the bridge docs.
394e6308b6dSThomas Bogendoerfer 	 */
395e6308b6dSThomas Bogendoerfer 	bridge_set(bc, b_int_mode, (1UL << pin));
396e6308b6dSThomas Bogendoerfer 
397e6308b6dSThomas Bogendoerfer 	/*
398e6308b6dSThomas Bogendoerfer 	 * We assume the bridge to have a 1:1 mapping between devices
399e6308b6dSThomas Bogendoerfer 	 * (slots) and intr pins.
400e6308b6dSThomas Bogendoerfer 	 */
401e6308b6dSThomas Bogendoerfer 	device = bridge_read(bc, b_int_device);
402e6308b6dSThomas Bogendoerfer 	device &= ~(7 << (pin*3));
403e6308b6dSThomas Bogendoerfer 	device |= (pin << (pin*3));
404e6308b6dSThomas Bogendoerfer 	bridge_write(bc, b_int_device, device);
405e6308b6dSThomas Bogendoerfer 
406e6308b6dSThomas Bogendoerfer 	bridge_read(bc, b_wid_tflush);
407e6308b6dSThomas Bogendoerfer 	return 0;
408e6308b6dSThomas Bogendoerfer }
409e6308b6dSThomas Bogendoerfer 
bridge_domain_deactivate(struct irq_domain * domain,struct irq_data * irqd)410e6308b6dSThomas Bogendoerfer static void bridge_domain_deactivate(struct irq_domain *domain,
411e6308b6dSThomas Bogendoerfer 				     struct irq_data *irqd)
412e6308b6dSThomas Bogendoerfer {
413e6308b6dSThomas Bogendoerfer 	struct bridge_irq_chip_data *data = irqd->chip_data;
414e6308b6dSThomas Bogendoerfer 
415e6308b6dSThomas Bogendoerfer 	bridge_clr(data->bc, b_int_enable, (1 << irqd->hwirq));
416e6308b6dSThomas Bogendoerfer 	bridge_read(data->bc, b_wid_tflush);
417e6308b6dSThomas Bogendoerfer }
418e6308b6dSThomas Bogendoerfer 
419e6308b6dSThomas Bogendoerfer static const struct irq_domain_ops bridge_domain_ops = {
420e6308b6dSThomas Bogendoerfer 	.alloc      = bridge_domain_alloc,
421e6308b6dSThomas Bogendoerfer 	.free       = bridge_domain_free,
422e6308b6dSThomas Bogendoerfer 	.activate   = bridge_domain_activate,
423e6308b6dSThomas Bogendoerfer 	.deactivate = bridge_domain_deactivate
424e6308b6dSThomas Bogendoerfer };
425e6308b6dSThomas Bogendoerfer 
426a57140e9SThomas Bogendoerfer /*
427a57140e9SThomas Bogendoerfer  * All observed requests have pin == 1. We could have a global here, that
428a57140e9SThomas Bogendoerfer  * gets incremented and returned every time - unfortunately, pci_map_irq
429a57140e9SThomas Bogendoerfer  * may be called on the same device over and over, and need to return the
430a57140e9SThomas Bogendoerfer  * same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7].
431a57140e9SThomas Bogendoerfer  *
432a57140e9SThomas Bogendoerfer  * A given PCI device, in general, should be able to intr any of the cpus
433a57140e9SThomas Bogendoerfer  * on any one of the hubs connected to its xbow.
434a57140e9SThomas Bogendoerfer  */
bridge_map_irq(const struct pci_dev * dev,u8 slot,u8 pin)435a57140e9SThomas Bogendoerfer static int bridge_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
436a57140e9SThomas Bogendoerfer {
437a57140e9SThomas Bogendoerfer 	struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
438e6308b6dSThomas Bogendoerfer 	struct irq_alloc_info info;
439a57140e9SThomas Bogendoerfer 	int irq;
440a57140e9SThomas Bogendoerfer 
4412634e5a6SThomas Bogendoerfer 	switch (pin) {
4422634e5a6SThomas Bogendoerfer 	case PCI_INTERRUPT_UNKNOWN:
4432634e5a6SThomas Bogendoerfer 	case PCI_INTERRUPT_INTA:
4442634e5a6SThomas Bogendoerfer 	case PCI_INTERRUPT_INTC:
4452634e5a6SThomas Bogendoerfer 		pin = 0;
4462634e5a6SThomas Bogendoerfer 		break;
4472634e5a6SThomas Bogendoerfer 	case PCI_INTERRUPT_INTB:
4482634e5a6SThomas Bogendoerfer 	case PCI_INTERRUPT_INTD:
4492634e5a6SThomas Bogendoerfer 		pin = 1;
4502634e5a6SThomas Bogendoerfer 	}
4512634e5a6SThomas Bogendoerfer 
4522634e5a6SThomas Bogendoerfer 	irq = bc->pci_int[slot][pin];
453a57140e9SThomas Bogendoerfer 	if (irq == -1) {
454e6308b6dSThomas Bogendoerfer 		info.ctrl = bc;
455e6308b6dSThomas Bogendoerfer 		info.nasid = bc->nasid;
4562634e5a6SThomas Bogendoerfer 		info.pin = bc->int_mapping[slot][pin];
457e6308b6dSThomas Bogendoerfer 
458e6308b6dSThomas Bogendoerfer 		irq = irq_domain_alloc_irqs(bc->domain, 1, bc->nasid, &info);
459a57140e9SThomas Bogendoerfer 		if (irq < 0)
460a57140e9SThomas Bogendoerfer 			return irq;
461a57140e9SThomas Bogendoerfer 
4622634e5a6SThomas Bogendoerfer 		bc->pci_int[slot][pin] = irq;
463a57140e9SThomas Bogendoerfer 	}
464a57140e9SThomas Bogendoerfer 	return irq;
465a57140e9SThomas Bogendoerfer }
466a57140e9SThomas Bogendoerfer 
46729b261ffSThomas Bogendoerfer #define IOC3_SID(sid)	(PCI_VENDOR_ID_SGI | ((sid) << 16))
4685dc76a96SThomas Bogendoerfer 
bridge_setup_ip27_baseio6g(struct bridge_controller * bc)4695dc76a96SThomas Bogendoerfer static void bridge_setup_ip27_baseio6g(struct bridge_controller *bc)
4705dc76a96SThomas Bogendoerfer {
4715dc76a96SThomas Bogendoerfer 	bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP27_BASEIO6G);
4725dc76a96SThomas Bogendoerfer 	bc->ioc3_sid[6] = IOC3_SID(IOC3_SUBSYS_IP27_MIO);
4732634e5a6SThomas Bogendoerfer 	bc->int_mapping[2][1] = 4;
4742634e5a6SThomas Bogendoerfer 	bc->int_mapping[6][1] = 6;
4755dc76a96SThomas Bogendoerfer }
4765dc76a96SThomas Bogendoerfer 
bridge_setup_ip27_baseio(struct bridge_controller * bc)4775dc76a96SThomas Bogendoerfer static void bridge_setup_ip27_baseio(struct bridge_controller *bc)
4785dc76a96SThomas Bogendoerfer {
4795dc76a96SThomas Bogendoerfer 	bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP27_BASEIO);
4802634e5a6SThomas Bogendoerfer 	bc->int_mapping[2][1] = 4;
4815dc76a96SThomas Bogendoerfer }
4825dc76a96SThomas Bogendoerfer 
bridge_setup_ip29_baseio(struct bridge_controller * bc)4835dc76a96SThomas Bogendoerfer static void bridge_setup_ip29_baseio(struct bridge_controller *bc)
4845dc76a96SThomas Bogendoerfer {
4855dc76a96SThomas Bogendoerfer 	bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP29_SYSBOARD);
4862634e5a6SThomas Bogendoerfer 	bc->int_mapping[2][1] = 3;
4875dc76a96SThomas Bogendoerfer }
4885dc76a96SThomas Bogendoerfer 
bridge_setup_ip30_sysboard(struct bridge_controller * bc)4895dc76a96SThomas Bogendoerfer static void bridge_setup_ip30_sysboard(struct bridge_controller *bc)
4905dc76a96SThomas Bogendoerfer {
4915dc76a96SThomas Bogendoerfer 	bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP30_SYSBOARD);
4922634e5a6SThomas Bogendoerfer 	bc->int_mapping[2][1] = 4;
4935dc76a96SThomas Bogendoerfer }
4945dc76a96SThomas Bogendoerfer 
bridge_setup_menet(struct bridge_controller * bc)4955dc76a96SThomas Bogendoerfer static void bridge_setup_menet(struct bridge_controller *bc)
4965dc76a96SThomas Bogendoerfer {
4975dc76a96SThomas Bogendoerfer 	bc->ioc3_sid[0] = IOC3_SID(IOC3_SUBSYS_MENET);
4985dc76a96SThomas Bogendoerfer 	bc->ioc3_sid[1] = IOC3_SID(IOC3_SUBSYS_MENET);
4995dc76a96SThomas Bogendoerfer 	bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_MENET);
5005dc76a96SThomas Bogendoerfer 	bc->ioc3_sid[3] = IOC3_SID(IOC3_SUBSYS_MENET4);
5015dc76a96SThomas Bogendoerfer }
5025dc76a96SThomas Bogendoerfer 
bridge_setup_io7(struct bridge_controller * bc)5032c428871SThomas Bogendoerfer static void bridge_setup_io7(struct bridge_controller *bc)
5042c428871SThomas Bogendoerfer {
5052c428871SThomas Bogendoerfer 	bc->ioc3_sid[4] = IOC3_SID(IOC3_SUBSYS_IO7);
5062c428871SThomas Bogendoerfer }
5072c428871SThomas Bogendoerfer 
bridge_setup_io8(struct bridge_controller * bc)5082c428871SThomas Bogendoerfer static void bridge_setup_io8(struct bridge_controller *bc)
5092c428871SThomas Bogendoerfer {
5102c428871SThomas Bogendoerfer 	bc->ioc3_sid[4] = IOC3_SID(IOC3_SUBSYS_IO8);
5112c428871SThomas Bogendoerfer }
5122c428871SThomas Bogendoerfer 
bridge_setup_io9(struct bridge_controller * bc)5132c428871SThomas Bogendoerfer static void bridge_setup_io9(struct bridge_controller *bc)
5142c428871SThomas Bogendoerfer {
5152c428871SThomas Bogendoerfer 	bc->ioc3_sid[1] = IOC3_SID(IOC3_SUBSYS_IO9);
5162c428871SThomas Bogendoerfer }
5172c428871SThomas Bogendoerfer 
bridge_setup_ip34_fuel_sysboard(struct bridge_controller * bc)5182c428871SThomas Bogendoerfer static void bridge_setup_ip34_fuel_sysboard(struct bridge_controller *bc)
5192c428871SThomas Bogendoerfer {
5202c428871SThomas Bogendoerfer 	bc->ioc3_sid[4] = IOC3_SID(IOC3_SUBSYS_IP34_SYSBOARD);
5212c428871SThomas Bogendoerfer }
5222c428871SThomas Bogendoerfer 
5235dc76a96SThomas Bogendoerfer #define BRIDGE_BOARD_SETUP(_partno, _setup)	\
5245dc76a96SThomas Bogendoerfer 	{ .match = _partno, .setup = _setup }
5255dc76a96SThomas Bogendoerfer 
5265dc76a96SThomas Bogendoerfer static const struct {
5275dc76a96SThomas Bogendoerfer 	char *match;
5285dc76a96SThomas Bogendoerfer 	void (*setup)(struct bridge_controller *bc);
5295dc76a96SThomas Bogendoerfer } bridge_ioc3_devid[] = {
5305dc76a96SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-0734-", bridge_setup_ip27_baseio6g),
5315dc76a96SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-0880-", bridge_setup_ip27_baseio6g),
5325dc76a96SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-1023-", bridge_setup_ip27_baseio),
5335dc76a96SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-1124-", bridge_setup_ip27_baseio),
5345dc76a96SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-1025-", bridge_setup_ip29_baseio),
5355dc76a96SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-1244-", bridge_setup_ip29_baseio),
5365dc76a96SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-1389-", bridge_setup_ip29_baseio),
5375dc76a96SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-0887-", bridge_setup_ip30_sysboard),
5385dc76a96SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-1467-", bridge_setup_ip30_sysboard),
5395dc76a96SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-0873-", bridge_setup_menet),
5402c428871SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-1557-", bridge_setup_io7),
5412c428871SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-1673-", bridge_setup_io8),
5422c428871SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-1771-", bridge_setup_io9),
5432c428871SThomas Bogendoerfer 	BRIDGE_BOARD_SETUP("030-1707-", bridge_setup_ip34_fuel_sysboard),
5445dc76a96SThomas Bogendoerfer };
5455dc76a96SThomas Bogendoerfer 
bridge_setup_board(struct bridge_controller * bc,char * partnum)5465dc76a96SThomas Bogendoerfer static void bridge_setup_board(struct bridge_controller *bc, char *partnum)
5475dc76a96SThomas Bogendoerfer {
5485dc76a96SThomas Bogendoerfer 	int i;
5495dc76a96SThomas Bogendoerfer 
5505dc76a96SThomas Bogendoerfer 	for (i = 0; i < ARRAY_SIZE(bridge_ioc3_devid); i++)
5515dc76a96SThomas Bogendoerfer 		if (!strncmp(partnum, bridge_ioc3_devid[i].match,
5525dc76a96SThomas Bogendoerfer 			     strlen(bridge_ioc3_devid[i].match))) {
5535dc76a96SThomas Bogendoerfer 			bridge_ioc3_devid[i].setup(bc);
5545dc76a96SThomas Bogendoerfer 		}
5555dc76a96SThomas Bogendoerfer }
5565dc76a96SThomas Bogendoerfer 
bridge_nvmem_match(struct device * dev,const void * data)5575dc76a96SThomas Bogendoerfer static int bridge_nvmem_match(struct device *dev, const void *data)
5585dc76a96SThomas Bogendoerfer {
5595dc76a96SThomas Bogendoerfer 	const char *name = dev_name(dev);
5605dc76a96SThomas Bogendoerfer 	const char *prefix = data;
5615dc76a96SThomas Bogendoerfer 
5625dc76a96SThomas Bogendoerfer 	if (strlen(name) < strlen(prefix))
5635dc76a96SThomas Bogendoerfer 		return 0;
5645dc76a96SThomas Bogendoerfer 
5655dc76a96SThomas Bogendoerfer 	return memcmp(prefix, dev_name(dev), strlen(prefix)) == 0;
5665dc76a96SThomas Bogendoerfer }
5675dc76a96SThomas Bogendoerfer 
bridge_get_partnum(u64 baddr,char * partnum)5685dc76a96SThomas Bogendoerfer static int bridge_get_partnum(u64 baddr, char *partnum)
5695dc76a96SThomas Bogendoerfer {
5705dc76a96SThomas Bogendoerfer 	struct nvmem_device *nvmem;
5715dc76a96SThomas Bogendoerfer 	char prefix[24];
5725dc76a96SThomas Bogendoerfer 	u8 prom[64];
5735dc76a96SThomas Bogendoerfer 	int i, j;
5745dc76a96SThomas Bogendoerfer 	int ret;
5755dc76a96SThomas Bogendoerfer 
5765dc76a96SThomas Bogendoerfer 	snprintf(prefix, sizeof(prefix), "bridge-%012llx-0b-", baddr);
5775dc76a96SThomas Bogendoerfer 
5785dc76a96SThomas Bogendoerfer 	nvmem = nvmem_device_find(prefix, bridge_nvmem_match);
5795dc76a96SThomas Bogendoerfer 	if (IS_ERR(nvmem))
5805dc76a96SThomas Bogendoerfer 		return PTR_ERR(nvmem);
5815dc76a96SThomas Bogendoerfer 
5825dc76a96SThomas Bogendoerfer 	ret = nvmem_device_read(nvmem, 0, 64, prom);
5835dc76a96SThomas Bogendoerfer 	nvmem_device_put(nvmem);
5845dc76a96SThomas Bogendoerfer 
5855dc76a96SThomas Bogendoerfer 	if (ret != 64)
5865dc76a96SThomas Bogendoerfer 		return ret;
5875dc76a96SThomas Bogendoerfer 
5885dc76a96SThomas Bogendoerfer 	if (crc16(CRC16_INIT, prom, 32) != CRC16_VALID ||
5895dc76a96SThomas Bogendoerfer 	    crc16(CRC16_INIT, prom + 32, 32) != CRC16_VALID)
5905dc76a96SThomas Bogendoerfer 		return -EINVAL;
5915dc76a96SThomas Bogendoerfer 
5925dc76a96SThomas Bogendoerfer 	/* Assemble part number */
5935dc76a96SThomas Bogendoerfer 	j = 0;
5945dc76a96SThomas Bogendoerfer 	for (i = 0; i < 19; i++)
5955dc76a96SThomas Bogendoerfer 		if (prom[i + 11] != ' ')
5965dc76a96SThomas Bogendoerfer 			partnum[j++] = prom[i + 11];
5975dc76a96SThomas Bogendoerfer 
5985dc76a96SThomas Bogendoerfer 	for (i = 0; i < 6; i++)
5995dc76a96SThomas Bogendoerfer 		if (prom[i + 32] != ' ')
6005dc76a96SThomas Bogendoerfer 			partnum[j++] = prom[i + 32];
6015dc76a96SThomas Bogendoerfer 
6025dc76a96SThomas Bogendoerfer 	partnum[j] = 0;
6035dc76a96SThomas Bogendoerfer 
6045dc76a96SThomas Bogendoerfer 	return 0;
6055dc76a96SThomas Bogendoerfer }
6065dc76a96SThomas Bogendoerfer 
bridge_probe(struct platform_device * pdev)607a57140e9SThomas Bogendoerfer static int bridge_probe(struct platform_device *pdev)
608a57140e9SThomas Bogendoerfer {
609e6308b6dSThomas Bogendoerfer 	struct xtalk_bridge_platform_data *bd = dev_get_platdata(&pdev->dev);
610a57140e9SThomas Bogendoerfer 	struct device *dev = &pdev->dev;
611a57140e9SThomas Bogendoerfer 	struct bridge_controller *bc;
612a57140e9SThomas Bogendoerfer 	struct pci_host_bridge *host;
613e6308b6dSThomas Bogendoerfer 	struct irq_domain *domain, *parent;
614e6308b6dSThomas Bogendoerfer 	struct fwnode_handle *fn;
6155dc76a96SThomas Bogendoerfer 	char partnum[26];
616a57140e9SThomas Bogendoerfer 	int slot;
617a57140e9SThomas Bogendoerfer 	int err;
618e6308b6dSThomas Bogendoerfer 
6195dc76a96SThomas Bogendoerfer 	/* get part number from one wire prom */
6205dc76a96SThomas Bogendoerfer 	if (bridge_get_partnum(virt_to_phys((void *)bd->bridge_addr), partnum))
6215dc76a96SThomas Bogendoerfer 		return -EPROBE_DEFER; /* not available yet */
6225dc76a96SThomas Bogendoerfer 
623e6308b6dSThomas Bogendoerfer 	parent = irq_get_default_host();
624e6308b6dSThomas Bogendoerfer 	if (!parent)
625e6308b6dSThomas Bogendoerfer 		return -ENODEV;
626e6308b6dSThomas Bogendoerfer 	fn = irq_domain_alloc_named_fwnode("BRIDGE");
627e6308b6dSThomas Bogendoerfer 	if (!fn)
628e6308b6dSThomas Bogendoerfer 		return -ENOMEM;
629e6308b6dSThomas Bogendoerfer 	domain = irq_domain_create_hierarchy(parent, 0, 8, fn,
630e6308b6dSThomas Bogendoerfer 					     &bridge_domain_ops, NULL);
631e3beca48SThomas Gleixner 	if (!domain) {
632e6308b6dSThomas Bogendoerfer 		irq_domain_free_fwnode(fn);
633e6308b6dSThomas Bogendoerfer 		return -ENOMEM;
634e3beca48SThomas Gleixner 	}
635a57140e9SThomas Bogendoerfer 
636a57140e9SThomas Bogendoerfer 	pci_set_flags(PCI_PROBE_ONLY);
637a57140e9SThomas Bogendoerfer 
638a57140e9SThomas Bogendoerfer 	host = devm_pci_alloc_host_bridge(dev, sizeof(*bc));
639e6308b6dSThomas Bogendoerfer 	if (!host) {
640e6308b6dSThomas Bogendoerfer 		err = -ENOMEM;
641e6308b6dSThomas Bogendoerfer 		goto err_remove_domain;
642e6308b6dSThomas Bogendoerfer 	}
643a57140e9SThomas Bogendoerfer 
644a57140e9SThomas Bogendoerfer 	bc = pci_host_bridge_priv(host);
645a57140e9SThomas Bogendoerfer 
646a57140e9SThomas Bogendoerfer 	bc->busn.name		= "Bridge PCI busn";
647a57140e9SThomas Bogendoerfer 	bc->busn.start		= 0;
648a57140e9SThomas Bogendoerfer 	bc->busn.end		= 0xff;
649a57140e9SThomas Bogendoerfer 	bc->busn.flags		= IORESOURCE_BUS;
650a57140e9SThomas Bogendoerfer 
651e6308b6dSThomas Bogendoerfer 	bc->domain		= domain;
652e6308b6dSThomas Bogendoerfer 
653a57140e9SThomas Bogendoerfer 	pci_add_resource_offset(&host->windows, &bd->mem, bd->mem_offset);
654a57140e9SThomas Bogendoerfer 	pci_add_resource_offset(&host->windows, &bd->io, bd->io_offset);
655a57140e9SThomas Bogendoerfer 	pci_add_resource(&host->windows, &bc->busn);
656a57140e9SThomas Bogendoerfer 
657a57140e9SThomas Bogendoerfer 	err = devm_request_pci_bus_resources(dev, &host->windows);
658e6308b6dSThomas Bogendoerfer 	if (err < 0)
659e6308b6dSThomas Bogendoerfer 		goto err_free_resource;
660a57140e9SThomas Bogendoerfer 
661a57140e9SThomas Bogendoerfer 	bc->nasid = bd->nasid;
662a57140e9SThomas Bogendoerfer 
663a57140e9SThomas Bogendoerfer 	bc->baddr = (u64)bd->masterwid << 60 | PCI64_ATTR_BAR;
664a57140e9SThomas Bogendoerfer 	bc->base = (struct bridge_regs *)bd->bridge_addr;
665a57140e9SThomas Bogendoerfer 	bc->intr_addr = bd->intr_addr;
666a57140e9SThomas Bogendoerfer 
667a57140e9SThomas Bogendoerfer 	/*
668a57140e9SThomas Bogendoerfer 	 * Clear all pending interrupts.
669a57140e9SThomas Bogendoerfer 	 */
670a57140e9SThomas Bogendoerfer 	bridge_write(bc, b_int_rst_stat, BRIDGE_IRR_ALL_CLR);
671a57140e9SThomas Bogendoerfer 
672a57140e9SThomas Bogendoerfer 	/*
673a57140e9SThomas Bogendoerfer 	 * Until otherwise set up, assume all interrupts are from slot 0
674a57140e9SThomas Bogendoerfer 	 */
675a57140e9SThomas Bogendoerfer 	bridge_write(bc, b_int_device, 0x0);
676a57140e9SThomas Bogendoerfer 
677a57140e9SThomas Bogendoerfer 	/*
678a57140e9SThomas Bogendoerfer 	 * disable swapping for big windows
679a57140e9SThomas Bogendoerfer 	 */
680a57140e9SThomas Bogendoerfer 	bridge_clr(bc, b_wid_control,
681a57140e9SThomas Bogendoerfer 		   BRIDGE_CTRL_IO_SWAP | BRIDGE_CTRL_MEM_SWAP);
682a57140e9SThomas Bogendoerfer #ifdef CONFIG_PAGE_SIZE_4KB
683a57140e9SThomas Bogendoerfer 	bridge_clr(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
684a57140e9SThomas Bogendoerfer #else /* 16kB or larger */
685a57140e9SThomas Bogendoerfer 	bridge_set(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
686a57140e9SThomas Bogendoerfer #endif
687a57140e9SThomas Bogendoerfer 
688a57140e9SThomas Bogendoerfer 	/*
689a57140e9SThomas Bogendoerfer 	 * Hmm...  IRIX sets additional bits in the address which
690a57140e9SThomas Bogendoerfer 	 * are documented as reserved in the bridge docs.
691a57140e9SThomas Bogendoerfer 	 */
692a57140e9SThomas Bogendoerfer 	bridge_write(bc, b_wid_int_upper,
693a57140e9SThomas Bogendoerfer 		     ((bc->intr_addr >> 32) & 0xffff) | (bd->masterwid << 16));
694a57140e9SThomas Bogendoerfer 	bridge_write(bc, b_wid_int_lower, bc->intr_addr & 0xffffffff);
695a57140e9SThomas Bogendoerfer 	bridge_write(bc, b_dir_map, (bd->masterwid << 20));	/* DMA */
696a57140e9SThomas Bogendoerfer 	bridge_write(bc, b_int_enable, 0);
697a57140e9SThomas Bogendoerfer 
698a57140e9SThomas Bogendoerfer 	for (slot = 0; slot < 8; slot++) {
699a57140e9SThomas Bogendoerfer 		bridge_set(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
7002634e5a6SThomas Bogendoerfer 		bc->pci_int[slot][0] = -1;
7012634e5a6SThomas Bogendoerfer 		bc->pci_int[slot][1] = -1;
7022634e5a6SThomas Bogendoerfer 		/* default interrupt pin mapping */
7032634e5a6SThomas Bogendoerfer 		bc->int_mapping[slot][0] = slot;
7042634e5a6SThomas Bogendoerfer 		bc->int_mapping[slot][1] = slot ^ 4;
705a57140e9SThomas Bogendoerfer 	}
706a57140e9SThomas Bogendoerfer 	bridge_read(bc, b_wid_tflush);	  /* wait until Bridge PIO complete */
707a57140e9SThomas Bogendoerfer 
7085dc76a96SThomas Bogendoerfer 	bridge_setup_board(bc, partnum);
7095dc76a96SThomas Bogendoerfer 
710a57140e9SThomas Bogendoerfer 	host->dev.parent = dev;
711a57140e9SThomas Bogendoerfer 	host->sysdata = bc;
712a57140e9SThomas Bogendoerfer 	host->busnr = 0;
713a57140e9SThomas Bogendoerfer 	host->ops = &bridge_pci_ops;
714a57140e9SThomas Bogendoerfer 	host->map_irq = bridge_map_irq;
715a57140e9SThomas Bogendoerfer 	host->swizzle_irq = pci_common_swizzle;
716a57140e9SThomas Bogendoerfer 
717a57140e9SThomas Bogendoerfer 	err = pci_scan_root_bus_bridge(host);
718a57140e9SThomas Bogendoerfer 	if (err < 0)
719e6308b6dSThomas Bogendoerfer 		goto err_free_resource;
720a57140e9SThomas Bogendoerfer 
721a57140e9SThomas Bogendoerfer 	pci_bus_claim_resources(host->bus);
722a57140e9SThomas Bogendoerfer 	pci_bus_add_devices(host->bus);
723a57140e9SThomas Bogendoerfer 
724a57140e9SThomas Bogendoerfer 	platform_set_drvdata(pdev, host->bus);
725a57140e9SThomas Bogendoerfer 
726a57140e9SThomas Bogendoerfer 	return 0;
727e6308b6dSThomas Bogendoerfer 
728e6308b6dSThomas Bogendoerfer err_free_resource:
729e6308b6dSThomas Bogendoerfer 	pci_free_resource_list(&host->windows);
730e6308b6dSThomas Bogendoerfer err_remove_domain:
731e6308b6dSThomas Bogendoerfer 	irq_domain_remove(domain);
732ec016089SJon Derrick 	irq_domain_free_fwnode(fn);
733e6308b6dSThomas Bogendoerfer 	return err;
734a57140e9SThomas Bogendoerfer }
735a57140e9SThomas Bogendoerfer 
bridge_remove(struct platform_device * pdev)736*f7396eefSUwe Kleine-König static void bridge_remove(struct platform_device *pdev)
737a57140e9SThomas Bogendoerfer {
738a57140e9SThomas Bogendoerfer 	struct pci_bus *bus = platform_get_drvdata(pdev);
739e6308b6dSThomas Bogendoerfer 	struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
740ec016089SJon Derrick 	struct fwnode_handle *fn = bc->domain->fwnode;
741a57140e9SThomas Bogendoerfer 
742e6308b6dSThomas Bogendoerfer 	irq_domain_remove(bc->domain);
743ec016089SJon Derrick 	irq_domain_free_fwnode(fn);
744a57140e9SThomas Bogendoerfer 	pci_lock_rescan_remove();
745a57140e9SThomas Bogendoerfer 	pci_stop_root_bus(bus);
746a57140e9SThomas Bogendoerfer 	pci_remove_root_bus(bus);
747a57140e9SThomas Bogendoerfer 	pci_unlock_rescan_remove();
748a57140e9SThomas Bogendoerfer }
749a57140e9SThomas Bogendoerfer 
750a57140e9SThomas Bogendoerfer static struct platform_driver bridge_driver = {
751a57140e9SThomas Bogendoerfer 	.probe = bridge_probe,
752*f7396eefSUwe Kleine-König 	.remove_new = bridge_remove,
753a57140e9SThomas Bogendoerfer 	.driver = {
754a57140e9SThomas Bogendoerfer 		.name = "xtalk-bridge",
755a57140e9SThomas Bogendoerfer 	}
756a57140e9SThomas Bogendoerfer };
757a57140e9SThomas Bogendoerfer 
758a57140e9SThomas Bogendoerfer builtin_platform_driver(bridge_driver);
759