/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2013 Cavium, Inc.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <uapi/asm/bitfield.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#define PCI_CONFIG_ADDRESS 0xcf8
#define PCI_CONFIG_DATA 0xcfc
union pci_config_address {
struct {
__BITFIELD_FIELD(unsigned enable_bit : 1, /* 31 */
__BITFIELD_FIELD(unsigned reserved : 7, /* 30 .. 24 */
__BITFIELD_FIELD(unsigned bus_number : 8, /* 23 .. 16 */
__BITFIELD_FIELD(unsigned devfn_number : 8, /* 15 .. 8 */
__BITFIELD_FIELD(unsigned register_number : 8, /* 7 .. 0 */
)))));
};
u32 w;
};
int pcibios_plat_dev_init(struct pci_dev *dev)
{
return 0;
}
int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
return ((pin + slot) % 4)+ MIPS_IRQ_PCIA;
}
static void pci_virtio_guest_write_config_addr(struct pci_bus *bus,
unsigned int devfn, int reg)
{
union pci_config_address pca = { .w = 0 };
pca.register_number = reg;
pca.devfn_number = devfn;
pca.bus_number = bus->number;
pca.enable_bit = 1;
outl(pca.w, PCI_CONFIG_ADDRESS);
}
static int pci_virtio_guest_write_config(struct pci_bus *bus,
unsigned int devfn, int reg, int size, u32 val)
{
pci_virtio_guest_write_config_addr(bus, devfn, reg);
switch (size) {
case 1:
outb(val, PCI_CONFIG_DATA + (reg & 3));
break;
case 2:
outw(val, PCI_CONFIG_DATA + (reg & 2));
break;
case 4:
outl(val, PCI_CONFIG_DATA);
break;
}
return PCIBIOS_SUCCESSFUL;
}
static int pci_virtio_guest_read_config(struct pci_bus *bus, unsigned int devfn,
int reg, int size, u32 *val)
{
pci_virtio_guest_write_config_addr(bus, devfn, reg);
switch (size) {
case 1:
*val = inb(PCI_CONFIG_DATA + (reg & 3));
break;
case 2:
*val = inw(PCI_CONFIG_DATA + (reg & 2));
break;
case 4:
*val = inl(PCI_CONFIG_DATA);
break;
}
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops pci_virtio_guest_ops = {
.read = pci_virtio_guest_read_config,
.write = pci_virtio_guest_write_config,
};
static struct resource pci_virtio_guest_mem_resource = {
.name = "Virtio MEM",
.flags = IORESOURCE_MEM,
.start = 0x10000000,
.end = 0x1dffffff
};
static struct resource pci_virtio_guest_io_resource = {
.name = "Virtio IO",
.flags = IORESOURCE_IO,
.start = 0,
.end = 0xffff
};
static struct pci_controller pci_virtio_guest_controller = {
.pci_ops = &pci_virtio_guest_ops,
.mem_resource = &pci_virtio_guest_mem_resource,
.io_resource = &pci_virtio_guest_io_resource,
};
static int __init pci_virtio_guest_setup(void)
{
pr_err("pci_virtio_guest_setup\n");
/* Virtio comes pre-assigned */
pci_set_flags(PCI_PROBE_ONLY);
pci_virtio_guest_controller.io_map_base = mips_io_port_base;
register_pci_controller(&pci_virtio_guest_controller);
return 0;
}
arch_initcall(pci_virtio_guest_setup);