Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1// SPDX-License-Identifier: GPL-2.0
  2#include <linux/types.h>
  3#include <linux/pci.h>
  4#include <linux/kernel.h>
  5
  6#include <asm/mips-boards/bonito64.h>
  7
  8#include <loongson.h>
  9
 10#define PCI_ACCESS_READ  0
 11#define PCI_ACCESS_WRITE 1
 12
 13#define HT1LO_PCICFG_BASE      0x1a000000
 14#define HT1LO_PCICFG_BASE_TP1  0x1b000000
 15
 16static int loongson3_pci_config_access(unsigned char access_type,
 17		struct pci_bus *bus, unsigned int devfn,
 18		int where, u32 *data)
 19{
 20	unsigned char busnum = bus->number;
 21	int function = PCI_FUNC(devfn);
 22	int device = PCI_SLOT(devfn);
 23	int reg = where & ~3;
 24	void *addrp;
 25	u64 addr;
 26
 27	if (where < PCI_CFG_SPACE_SIZE) { /* standard config */
 28		addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
 29		if (busnum == 0) {
 30			if (device > 31)
 31				return PCIBIOS_DEVICE_NOT_FOUND;
 32			addrp = (void *)TO_UNCAC(HT1LO_PCICFG_BASE | addr);
 33		} else {
 34			addrp = (void *)TO_UNCAC(HT1LO_PCICFG_BASE_TP1 | addr);
 35		}
 36	} else if (where < PCI_CFG_SPACE_EXP_SIZE) {  /* extended config */
 37		struct pci_dev *rootdev;
 38
 39		rootdev = pci_get_domain_bus_and_slot(0, 0, 0);
 40		if (!rootdev)
 41			return PCIBIOS_DEVICE_NOT_FOUND;
 42
 43		addr = pci_resource_start(rootdev, 3);
 44		if (!addr)
 45			return PCIBIOS_DEVICE_NOT_FOUND;
 46
 47		addr |= busnum << 20 | device << 15 | function << 12 | reg;
 48		addrp = (void *)TO_UNCAC(addr);
 49	} else {
 50		return PCIBIOS_DEVICE_NOT_FOUND;
 51	}
 52
 53	if (access_type == PCI_ACCESS_WRITE)
 54		writel(*data, addrp);
 55	else {
 56		*data = readl(addrp);
 57		if (*data == 0xffffffff) {
 58			*data = -1;
 59			return PCIBIOS_DEVICE_NOT_FOUND;
 60		}
 61	}
 62	return PCIBIOS_SUCCESSFUL;
 63}
 64
 65static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn,
 66				 int where, int size, u32 *val)
 67{
 68	u32 data = 0;
 69	int ret = loongson3_pci_config_access(PCI_ACCESS_READ,
 70			bus, devfn, where, &data);
 71
 72	if (ret != PCIBIOS_SUCCESSFUL)
 73		return ret;
 74
 75	if (size == 1)
 76		*val = (data >> ((where & 3) << 3)) & 0xff;
 77	else if (size == 2)
 78		*val = (data >> ((where & 3) << 3)) & 0xffff;
 79	else
 80		*val = data;
 81
 82	return PCIBIOS_SUCCESSFUL;
 83}
 84
 85static int loongson3_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn,
 86				  int where, int size, u32 val)
 87{
 88	u32 data = 0;
 89	int ret;
 90
 91	if (size == 4)
 92		data = val;
 93	else {
 94		ret = loongson3_pci_config_access(PCI_ACCESS_READ,
 95				bus, devfn, where, &data);
 96		if (ret != PCIBIOS_SUCCESSFUL)
 97			return ret;
 98
 99		if (size == 1)
100			data = (data & ~(0xff << ((where & 3) << 3))) |
101			    (val << ((where & 3) << 3));
102		else if (size == 2)
103			data = (data & ~(0xffff << ((where & 3) << 3))) |
104			    (val << ((where & 3) << 3));
105	}
106
107	ret = loongson3_pci_config_access(PCI_ACCESS_WRITE,
108			bus, devfn, where, &data);
109
110	return ret;
111}
112
113struct pci_ops loongson_pci_ops = {
114	.read = loongson3_pci_pcibios_read,
115	.write = loongson3_pci_pcibios_write
116};