diff options
Diffstat (limited to 'arch/mips/pci/ops-loongson3.c')
| -rw-r--r-- | arch/mips/pci/ops-loongson3.c | 101 | 
1 files changed, 101 insertions, 0 deletions
diff --git a/arch/mips/pci/ops-loongson3.c b/arch/mips/pci/ops-loongson3.c new file mode 100644 index 00000000000..46ed541a3ec --- /dev/null +++ b/arch/mips/pci/ops-loongson3.c @@ -0,0 +1,101 @@ +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> + +#include <asm/mips-boards/bonito64.h> + +#include <loongson.h> + +#define PCI_ACCESS_READ  0 +#define PCI_ACCESS_WRITE 1 + +#define HT1LO_PCICFG_BASE      0x1a000000 +#define HT1LO_PCICFG_BASE_TP1  0x1b000000 + +static int loongson3_pci_config_access(unsigned char access_type, +		struct pci_bus *bus, unsigned int devfn, +		int where, u32 *data) +{ +	unsigned char busnum = bus->number; +	u_int64_t addr, type; +	void *addrp; +	int device = PCI_SLOT(devfn); +	int function = PCI_FUNC(devfn); +	int reg = where & ~3; + +	addr = (busnum << 16) | (device << 11) | (function << 8) | reg; +	if (busnum == 0) { +		if (device > 31) +			return PCIBIOS_DEVICE_NOT_FOUND; +		addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE) | (addr & 0xffff)); +		type = 0; + +	} else { +		addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE_TP1) | (addr)); +		type = 0x10000; +	} + +	if (access_type == PCI_ACCESS_WRITE) +		writel(*data, addrp); +	else { +		*data = readl(addrp); +		if (*data == 0xffffffff) { +			*data = -1; +			return PCIBIOS_DEVICE_NOT_FOUND; +		} +	} +	return PCIBIOS_SUCCESSFUL; +} + +static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn, +				 int where, int size, u32 *val) +{ +	u32 data = 0; +	int ret = loongson3_pci_config_access(PCI_ACCESS_READ, +			bus, devfn, where, &data); + +	if (ret != PCIBIOS_SUCCESSFUL) +		return ret; + +	if (size == 1) +		*val = (data >> ((where & 3) << 3)) & 0xff; +	else if (size == 2) +		*val = (data >> ((where & 3) << 3)) & 0xffff; +	else +		*val = data; + +	return PCIBIOS_SUCCESSFUL; +} + +static int loongson3_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn, +				  int where, int size, u32 val) +{ +	u32 data = 0; +	int ret; + +	if (size == 4) +		data = val; +	else { +		ret = loongson3_pci_config_access(PCI_ACCESS_READ, +				bus, devfn, where, &data); +		if (ret != PCIBIOS_SUCCESSFUL) +			return ret; + +		if (size == 1) +			data = (data & ~(0xff << ((where & 3) << 3))) | +			    (val << ((where & 3) << 3)); +		else if (size == 2) +			data = (data & ~(0xffff << ((where & 3) << 3))) | +			    (val << ((where & 3) << 3)); +	} + +	ret = loongson3_pci_config_access(PCI_ACCESS_WRITE, +			bus, devfn, where, &data); + +	return ret; +} + +struct pci_ops loongson_pci_ops = { +	.read = loongson3_pci_pcibios_read, +	.write = loongson3_pci_pcibios_write +};  | 
