aboutsummaryrefslogtreecommitdiff
path: root/src/hw/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hw/pci.c')
-rw-r--r--src/hw/pci.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/hw/pci.c b/src/hw/pci.c
index ecc724b..3f35250 100644
--- a/src/hw/pci.c
+++ b/src/hw/pci.c
@@ -31,8 +31,40 @@ static u32 ioconfig_cmd(u16 bdf, u32 addr)
return 0x80000000 | (bdf << 8) | (addr & 0xfc);
}
+/*
+ * Memory mapped I/O
+ *
+ * readX()/writeX() do byteswapping and take an ioremapped address
+ * __raw_readX()/__raw_writeX() don't byteswap and take an ioremapped address.
+ * gsc_*() don't byteswap and operate on physical addresses;
+ * eg dev->hpa or 0xfee00000.
+ */
+
+/* each elroy has 0x2000 offset */
+#define ELROY_MAX_BUSSES 4
+unsigned long elroy_offset(u16 bdf)
+{
+ static const int elroy_hpa_offsets[ELROY_MAX_BUSSES] = { 0x30000, 0x32000, 0x38000, 0x3c000 };
+ int bus = pci_bdf_to_bus(bdf);
+ if (bus >= ELROY_MAX_BUSSES)
+ return -1UL;
+ return elroy_hpa_offsets[bus] - elroy_hpa_offsets[0];
+}
+
+void *elroy_port(unsigned long port, unsigned long offs)
+{
+ return (void *)(port + offs);
+}
+
void pci_config_writel(u16 bdf, u32 addr, u32 val)
{
+ if (has_astro) {
+ unsigned long offs = elroy_offset(bdf);
+ if (offs == -1UL)
+ return;
+ writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr));
+ writel(elroy_port(PORT_PCI_DATA, offs), val);
+ } else
if (!MODESEGMENT && mmconfig) {
writel(mmconfig_addr(bdf, addr), val);
} else {
@@ -43,6 +75,13 @@ void pci_config_writel(u16 bdf, u32 addr, u32 val)
void pci_config_writew(u16 bdf, u32 addr, u16 val)
{
+ if (has_astro) {
+ unsigned long offs = elroy_offset(bdf);
+ if (offs == -1UL)
+ return;
+ writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr));
+ writew(elroy_port(PORT_PCI_DATA + (addr & 2), offs), val);
+ } else
if (!MODESEGMENT && mmconfig) {
writew(mmconfig_addr(bdf, addr), val);
} else {
@@ -53,6 +92,13 @@ void pci_config_writew(u16 bdf, u32 addr, u16 val)
void pci_config_writeb(u16 bdf, u32 addr, u8 val)
{
+ if (has_astro) {
+ unsigned long offs = elroy_offset(bdf);
+ if (offs == -1UL)
+ return;
+ writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr));
+ writeb(elroy_port(PORT_PCI_DATA + (addr & 3), offs), val);
+ } else
if (!MODESEGMENT && mmconfig) {
writeb(mmconfig_addr(bdf, addr), val);
} else {
@@ -63,6 +109,13 @@ void pci_config_writeb(u16 bdf, u32 addr, u8 val)
u32 pci_config_readl(u16 bdf, u32 addr)
{
+ if (has_astro) {
+ unsigned long offs = elroy_offset(bdf);
+ if (offs == -1UL)
+ return -1;
+ writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr));
+ return readl(elroy_port(PORT_PCI_DATA, offs));
+ } else
if (!MODESEGMENT && mmconfig) {
return readl(mmconfig_addr(bdf, addr));
} else {
@@ -73,6 +126,13 @@ u32 pci_config_readl(u16 bdf, u32 addr)
u16 pci_config_readw(u16 bdf, u32 addr)
{
+ if (has_astro) {
+ unsigned long offs = elroy_offset(bdf);
+ if (offs == -1UL)
+ return -1;
+ writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr));
+ return readw(elroy_port(PORT_PCI_DATA + (addr & 2), offs));
+ } else
if (!MODESEGMENT && mmconfig) {
return readw(mmconfig_addr(bdf, addr));
} else {
@@ -83,6 +143,13 @@ u16 pci_config_readw(u16 bdf, u32 addr)
u8 pci_config_readb(u16 bdf, u32 addr)
{
+ if (has_astro) {
+ unsigned long offs = elroy_offset(bdf);
+ if (offs == -1UL)
+ return -1;
+ writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr));
+ return readb(elroy_port(PORT_PCI_DATA + (addr & 3), offs));
+ } else
if (!MODESEGMENT && mmconfig) {
return readb(mmconfig_addr(bdf, addr));
} else {