1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2013 Cavium, Inc.
7 */
8
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/interrupt.h>
12#include <linux/pci.h>
13
14#include <uapi/asm/bitfield.h>
15#include <asm/byteorder.h>
16#include <asm/io.h>
17
18#define PCI_CONFIG_ADDRESS	0xcf8
19#define PCI_CONFIG_DATA		0xcfc
20
21union pci_config_address {
22	struct {
23		__BITFIELD_FIELD(unsigned enable_bit	  : 1,	/* 31       */
24		__BITFIELD_FIELD(unsigned reserved	  : 7,	/* 30 .. 24 */
25		__BITFIELD_FIELD(unsigned bus_number	  : 8,	/* 23 .. 16 */
26		__BITFIELD_FIELD(unsigned devfn_number	  : 8,	/* 15 .. 8  */
27		__BITFIELD_FIELD(unsigned register_number : 8,	/* 7  .. 0  */
28		)))));
29	};
30	u32 w;
31};
32
33int pcibios_plat_dev_init(struct pci_dev *dev)
34{
35	return 0;
36}
37
38int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
39{
40	return ((pin + slot) % 4)+ MIPS_IRQ_PCIA;
41}
42
43static void pci_virtio_guest_write_config_addr(struct pci_bus *bus,
44					unsigned int devfn, int reg)
45{
46	union pci_config_address pca = { .w = 0 };
47
48	pca.register_number = reg;
49	pca.devfn_number = devfn;
50	pca.bus_number = bus->number;
51	pca.enable_bit = 1;
52
53	outl(pca.w, PCI_CONFIG_ADDRESS);
54}
55
56static int pci_virtio_guest_write_config(struct pci_bus *bus,
57		unsigned int devfn, int reg, int size, u32 val)
58{
59	pci_virtio_guest_write_config_addr(bus, devfn, reg);
60
61	switch (size) {
62	case 1:
63		outb(val, PCI_CONFIG_DATA + (reg & 3));
64		break;
65	case 2:
66		outw(val, PCI_CONFIG_DATA + (reg & 2));
67		break;
68	case 4:
69		outl(val, PCI_CONFIG_DATA);
70		break;
71	}
72
73	return PCIBIOS_SUCCESSFUL;
74}
75
76static int pci_virtio_guest_read_config(struct pci_bus *bus, unsigned int devfn,
77					int reg, int size, u32 *val)
78{
79	pci_virtio_guest_write_config_addr(bus, devfn, reg);
80
81	switch (size) {
82	case 1:
83		*val = inb(PCI_CONFIG_DATA + (reg & 3));
84		break;
85	case 2:
86		*val = inw(PCI_CONFIG_DATA + (reg & 2));
87		break;
88	case 4:
89		*val = inl(PCI_CONFIG_DATA);
90		break;
91	}
92	return PCIBIOS_SUCCESSFUL;
93}
94
95static struct pci_ops pci_virtio_guest_ops = {
96	.read  = pci_virtio_guest_read_config,
97	.write = pci_virtio_guest_write_config,
98};
99
100static struct resource pci_virtio_guest_mem_resource = {
101	.name = "Virtio MEM",
102	.flags = IORESOURCE_MEM,
103	.start	= 0x10000000,
104	.end	= 0x1dffffff
105};
106
107static struct resource pci_virtio_guest_io_resource = {
108	.name = "Virtio IO",
109	.flags = IORESOURCE_IO,
110	.start	= 0,
111	.end	= 0xffff
112};
113
114static struct pci_controller pci_virtio_guest_controller = {
115	.pci_ops = &pci_virtio_guest_ops,
116	.mem_resource = &pci_virtio_guest_mem_resource,
117	.io_resource = &pci_virtio_guest_io_resource,
118};
119
120static int __init pci_virtio_guest_setup(void)
121{
122	pr_err("pci_virtio_guest_setup\n");
123
124	/* Virtio comes pre-assigned */
125	pci_set_flags(PCI_PROBE_ONLY);
126
127	pci_virtio_guest_controller.io_map_base = mips_io_port_base;
128	register_pci_controller(&pci_virtio_guest_controller);
129	return 0;
130}
131arch_initcall(pci_virtio_guest_setup);
132