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