xref: /openbmc/linux/arch/sh/drivers/pci/ops-sh7786.c (revision 597473720f4dc69749542bfcfed4a927a43d935e)
1*ff4a7481SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
266765fe1SPaul Mundt /*
366765fe1SPaul Mundt  * Generic SH7786 PCI-Express operations.
466765fe1SPaul Mundt  *
57656e248SPaul Mundt  *  Copyright (C) 2009 - 2010  Paul Mundt
666765fe1SPaul Mundt  */
766765fe1SPaul Mundt #include <linux/kernel.h>
866765fe1SPaul Mundt #include <linux/init.h>
966765fe1SPaul Mundt #include <linux/pci.h>
1066765fe1SPaul Mundt #include <linux/io.h>
1166765fe1SPaul Mundt #include <linux/spinlock.h>
1266765fe1SPaul Mundt #include "pcie-sh7786.h"
1366765fe1SPaul Mundt 
1466765fe1SPaul Mundt enum {
1566765fe1SPaul Mundt 	PCI_ACCESS_READ,
1666765fe1SPaul Mundt 	PCI_ACCESS_WRITE,
1766765fe1SPaul Mundt };
1866765fe1SPaul Mundt 
sh7786_pcie_config_access(unsigned char access_type,struct pci_bus * bus,unsigned int devfn,int where,u32 * data)1966765fe1SPaul Mundt static int sh7786_pcie_config_access(unsigned char access_type,
2066765fe1SPaul Mundt 		struct pci_bus *bus, unsigned int devfn, int where, u32 *data)
2166765fe1SPaul Mundt {
2266765fe1SPaul Mundt 	struct pci_channel *chan = bus->sysdata;
232c65d75eSPaul Mundt 	int dev, func, type, reg;
2466765fe1SPaul Mundt 
2566765fe1SPaul Mundt 	dev = PCI_SLOT(devfn);
2666765fe1SPaul Mundt 	func = PCI_FUNC(devfn);
2765c23f54SPaul Mundt 	type = !!bus->parent;
282c65d75eSPaul Mundt 	reg = where & ~3;
2966765fe1SPaul Mundt 
3066765fe1SPaul Mundt 	if (bus->number > 255 || dev > 31 || func > 7)
3166765fe1SPaul Mundt 		return PCIBIOS_FUNC_NOT_SUPPORTED;
322c65d75eSPaul Mundt 
332c65d75eSPaul Mundt 	/*
342c65d75eSPaul Mundt 	 * While each channel has its own memory-mapped extended config
352c65d75eSPaul Mundt 	 * space, it's generally only accessible when in endpoint mode.
362c65d75eSPaul Mundt 	 * When in root complex mode, the controller is unable to target
372c65d75eSPaul Mundt 	 * itself with either type 0 or type 1 accesses, and indeed, any
382c65d75eSPaul Mundt 	 * controller initiated target transfer to its own config space
392c65d75eSPaul Mundt 	 * result in a completer abort.
402c65d75eSPaul Mundt 	 *
412c65d75eSPaul Mundt 	 * Each channel effectively only supports a single device, but as
422c65d75eSPaul Mundt 	 * the same channel <-> device access works for any PCI_SLOT()
432c65d75eSPaul Mundt 	 * value, we cheat a bit here and bind the controller's config
442c65d75eSPaul Mundt 	 * space to devfn 0 in order to enable self-enumeration. In this
452c65d75eSPaul Mundt 	 * case the regular PAR/PDR path is sidelined and the mangled
462c65d75eSPaul Mundt 	 * config access itself is initiated as a SuperHyway transaction.
472c65d75eSPaul Mundt 	 */
482c65d75eSPaul Mundt 	if (pci_is_root_bus(bus)) {
492c65d75eSPaul Mundt 		if (dev == 0) {
502c65d75eSPaul Mundt 			if (access_type == PCI_ACCESS_READ)
512c65d75eSPaul Mundt 				*data = pci_read_reg(chan, PCI_REG(reg));
522c65d75eSPaul Mundt 			else
532c65d75eSPaul Mundt 				pci_write_reg(chan, *data, PCI_REG(reg));
542c65d75eSPaul Mundt 
552c65d75eSPaul Mundt 			return PCIBIOS_SUCCESSFUL;
562c65d75eSPaul Mundt 		} else if (dev > 1)
5766765fe1SPaul Mundt 			return PCIBIOS_DEVICE_NOT_FOUND;
582c65d75eSPaul Mundt 	}
5966765fe1SPaul Mundt 
607656e248SPaul Mundt 	/* Clear errors */
617656e248SPaul Mundt 	pci_write_reg(chan, pci_read_reg(chan, SH4A_PCIEERRFR), SH4A_PCIEERRFR);
627656e248SPaul Mundt 
6366765fe1SPaul Mundt 	/* Set the PIO address */
6466765fe1SPaul Mundt 	pci_write_reg(chan, (bus->number << 24) | (dev << 19) |
652c65d75eSPaul Mundt 				(func << 16) | reg, SH4A_PCIEPAR);
6666765fe1SPaul Mundt 
6766765fe1SPaul Mundt 	/* Enable the configuration access */
6865c23f54SPaul Mundt 	pci_write_reg(chan, (1 << 31) | (type << 8), SH4A_PCIEPCTLR);
697656e248SPaul Mundt 
707656e248SPaul Mundt 	/* Check for errors */
717656e248SPaul Mundt 	if (pci_read_reg(chan, SH4A_PCIEERRFR) & 0x10)
727656e248SPaul Mundt 		return PCIBIOS_DEVICE_NOT_FOUND;
732c65d75eSPaul Mundt 
747656e248SPaul Mundt 	/* Check for master and target aborts */
757656e248SPaul Mundt 	if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
767656e248SPaul Mundt 		return PCIBIOS_DEVICE_NOT_FOUND;
7766765fe1SPaul Mundt 
7866765fe1SPaul Mundt 	if (access_type == PCI_ACCESS_READ)
7966765fe1SPaul Mundt 		*data = pci_read_reg(chan, SH4A_PCIEPDR);
8066765fe1SPaul Mundt 	else
8166765fe1SPaul Mundt 		pci_write_reg(chan, *data, SH4A_PCIEPDR);
8266765fe1SPaul Mundt 
83bdf74990SPaul Mundt 	/* Disable the configuration access */
84bdf74990SPaul Mundt 	pci_write_reg(chan, 0, SH4A_PCIEPCTLR);
85bdf74990SPaul Mundt 
8666765fe1SPaul Mundt 	return PCIBIOS_SUCCESSFUL;
8766765fe1SPaul Mundt }
8866765fe1SPaul Mundt 
sh7786_pcie_read(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 * val)8966765fe1SPaul Mundt static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn,
9066765fe1SPaul Mundt 			    int where, int size, u32 *val)
9166765fe1SPaul Mundt {
9266765fe1SPaul Mundt 	unsigned long flags;
9366765fe1SPaul Mundt 	int ret;
9466765fe1SPaul Mundt 	u32 data;
9566765fe1SPaul Mundt 
9666765fe1SPaul Mundt         if ((size == 2) && (where & 1))
9766765fe1SPaul Mundt 		return PCIBIOS_BAD_REGISTER_NUMBER;
9866765fe1SPaul Mundt 	else if ((size == 4) && (where & 3))
9966765fe1SPaul Mundt 		return PCIBIOS_BAD_REGISTER_NUMBER;
10066765fe1SPaul Mundt 
10139a90865SPaul Mundt 	raw_spin_lock_irqsave(&pci_config_lock, flags);
10266765fe1SPaul Mundt 	ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
10366765fe1SPaul Mundt 					devfn, where, &data);
1047656e248SPaul Mundt 	if (ret != PCIBIOS_SUCCESSFUL) {
1057656e248SPaul Mundt 		*val = 0xffffffff;
10666765fe1SPaul Mundt 		goto out;
1077656e248SPaul Mundt 	}
10866765fe1SPaul Mundt 
10966765fe1SPaul Mundt 	if (size == 1)
11066765fe1SPaul Mundt 		*val = (data >> ((where & 3) << 3)) & 0xff;
11166765fe1SPaul Mundt 	else if (size == 2)
11266765fe1SPaul Mundt 		*val = (data >> ((where & 2) << 3)) & 0xffff;
11366765fe1SPaul Mundt 	else
11466765fe1SPaul Mundt 		*val = data;
11566765fe1SPaul Mundt 
11666765fe1SPaul Mundt 	dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x "
11766765fe1SPaul Mundt 		"where=0x%04x size=%d val=0x%08lx\n", bus->number,
11866765fe1SPaul Mundt 		devfn, where, size, (unsigned long)*val);
11966765fe1SPaul Mundt 
12066765fe1SPaul Mundt out:
12139a90865SPaul Mundt 	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
12266765fe1SPaul Mundt 	return ret;
12366765fe1SPaul Mundt }
12466765fe1SPaul Mundt 
sh7786_pcie_write(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 val)12566765fe1SPaul Mundt static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn,
12666765fe1SPaul Mundt 			     int where, int size, u32 val)
12766765fe1SPaul Mundt {
12866765fe1SPaul Mundt 	unsigned long flags;
12966765fe1SPaul Mundt 	int shift, ret;
13066765fe1SPaul Mundt 	u32 data;
13166765fe1SPaul Mundt 
13266765fe1SPaul Mundt         if ((size == 2) && (where & 1))
13366765fe1SPaul Mundt 		return PCIBIOS_BAD_REGISTER_NUMBER;
13466765fe1SPaul Mundt 	else if ((size == 4) && (where & 3))
13566765fe1SPaul Mundt 		return PCIBIOS_BAD_REGISTER_NUMBER;
13666765fe1SPaul Mundt 
13739a90865SPaul Mundt 	raw_spin_lock_irqsave(&pci_config_lock, flags);
13866765fe1SPaul Mundt 	ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
13966765fe1SPaul Mundt 					devfn, where, &data);
14066765fe1SPaul Mundt 	if (ret != PCIBIOS_SUCCESSFUL)
14166765fe1SPaul Mundt 		goto out;
14266765fe1SPaul Mundt 
14366765fe1SPaul Mundt 	dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x "
14466765fe1SPaul Mundt 		"where=0x%04x size=%d val=%08lx\n", bus->number,
14566765fe1SPaul Mundt 		devfn, where, size, (unsigned long)val);
14666765fe1SPaul Mundt 
14766765fe1SPaul Mundt 	if (size == 1) {
14866765fe1SPaul Mundt 		shift = (where & 3) << 3;
14966765fe1SPaul Mundt 		data &= ~(0xff << shift);
15066765fe1SPaul Mundt 		data |= ((val & 0xff) << shift);
15166765fe1SPaul Mundt 	} else if (size == 2) {
15266765fe1SPaul Mundt 		shift = (where & 2) << 3;
15366765fe1SPaul Mundt 		data &= ~(0xffff << shift);
15466765fe1SPaul Mundt 		data |= ((val & 0xffff) << shift);
15566765fe1SPaul Mundt 	} else
15666765fe1SPaul Mundt 		data = val;
15766765fe1SPaul Mundt 
15866765fe1SPaul Mundt 	ret = sh7786_pcie_config_access(PCI_ACCESS_WRITE, bus,
15966765fe1SPaul Mundt 					devfn, where, &data);
16066765fe1SPaul Mundt out:
16139a90865SPaul Mundt 	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
16266765fe1SPaul Mundt 	return ret;
16366765fe1SPaul Mundt }
16466765fe1SPaul Mundt 
16566765fe1SPaul Mundt struct pci_ops sh7786_pci_ops = {
16666765fe1SPaul Mundt 	.read	= sh7786_pcie_read,
16766765fe1SPaul Mundt 	.write	= sh7786_pcie_write,
16866765fe1SPaul Mundt };
169