From c18730a60d89ddd809fe232a320a20188747bb8a Mon Sep 17 00:00:00 2001 From: Adam Madsen Date: Fri, 13 Nov 2020 17:22:13 -0600 Subject: [PATCH] [amd] common: Map port I/O space (proper way to access certain ATOM registers?) --- src/amd/common.c | 20 ++++++++++++- src/amd/common.h | 3 ++ src/amd/firmware.c | 72 ++++++++++++++++++++++++++++++++++++++++++++-- src/amd/firmware.h | 1 + 4 files changed, 93 insertions(+), 3 deletions(-) diff --git a/src/amd/common.c b/src/amd/common.c index e9731d7..c9b4fc0 100644 --- a/src/amd/common.c +++ b/src/amd/common.c @@ -32,7 +32,7 @@ int amd_common_pre_reset(struct vendor_reset_dev *dev) { struct amd_vendor_private *priv; struct pci_dev *pdev = dev->pdev; - int ret; + int ret, i; /* disable bus reset for the card, seems to be an issue with all of em */ pdev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET; @@ -58,6 +58,18 @@ int amd_common_pre_reset(struct vendor_reset_dev *dev) goto err_free; } + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) + { + if (pci_resource_flags(pdev, i) & IORESOURCE_IO) + { + priv->rio_mem_size = pci_resource_len(pdev, i); + priv->rio_mem = pci_iomap(pdev, i, priv->rio_mem_size); + break; + } + } + if (!priv->rio_mem) + pci_warn(pdev, "Could not map I/O\n"); + pci_set_power_state(pdev, PCI_D0); pci_clear_master(pdev); pci_save_state(pdev); @@ -82,6 +94,12 @@ int amd_common_post_reset(struct vendor_reset_dev *dev) priv->mmio = NULL; } + if (priv->rio_mem) + { + pci_iounmap(pdev, priv->rio_mem); + priv->rio_mem = NULL; + } + if (priv->saved_state) { pci_load_and_free_saved_state(pdev, &priv->saved_state); diff --git a/src/amd/common.h b/src/amd/common.h index 77e2d14..dd35c22 100644 --- a/src/amd/common.h +++ b/src/amd/common.h @@ -108,6 +108,9 @@ struct amd_vendor_private resource_size_t mmio_base; resource_size_t mmio_size; uint32_t __iomem *mmio; + + resource_size_t rio_mem_size; + uint32_t __iomem *rio_mem; }; static inline struct amd_vendor_private *adev_to_amd_private(struct amd_fake_dev *adev) diff --git a/src/amd/firmware.c b/src/amd/firmware.c index c9d7f82..b0049a4 100644 --- a/src/amd/firmware.c +++ b/src/amd/firmware.c @@ -26,6 +26,47 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "firmware.h" #define to_adev(info) ((struct amd_fake_dev *)container_of(info, struct amd_fake_dev, card_info)) +#define RREG32_IO(reg) amdgpu_io_rreg(adev, (reg)) +#define WREG32_IO(reg, v) amdgpu_io_wreg(adev, (reg), (v)) + +/** + * amdgpu_io_rreg - read an IO register + * + * @adev: amdgpu_device pointer + * @reg: dword aligned register offset + * + * Returns the 32 bit value from the offset specified. + */ +u32 amdgpu_io_rreg(struct amd_fake_dev *adev, u32 reg) +{ + if ((reg * 4) < adev_to_amd_private(adev)->rio_mem_size) + return ioread32(adev_to_amd_private(adev)->rio_mem + (reg * 4)); + else + { + iowrite32((reg * 4), adev_to_amd_private(adev)->rio_mem + (mmMM_INDEX * 4)); + return ioread32(adev_to_amd_private(adev)->rio_mem + (mmMM_DATA * 4)); + } +} + +/** + * amdgpu_io_wreg - write to an IO register + * + * @adev: amdgpu_device pointer + * @reg: dword aligned register offset + * @v: 32 bit value to write to the register + * + * Writes the value specified to the offset specified. + */ +void amdgpu_io_wreg(struct amd_fake_dev *adev, u32 reg, u32 v) +{ + if ((reg * 4) < adev_to_amd_private(adev)->rio_mem_size) + iowrite32(v, adev_to_amd_private(adev)->rio_mem + (reg * 4)); + else + { + iowrite32((reg * 4), adev_to_amd_private(adev)->rio_mem + (mmMM_INDEX * 4)); + iowrite32(v, adev_to_amd_private(adev)->rio_mem + (mmMM_DATA * 4)); + } +} static uint32_t null_read(struct card_info *info, uint32_t reg) { @@ -52,6 +93,22 @@ static uint32_t reg_read(struct card_info *info, uint32_t reg) return r; } +static uint32_t ioreg_read(struct card_info *info, uint32_t reg) +{ + struct amd_fake_dev *adev = to_adev(info); + uint32_t r; + + r = RREG32_IO(reg); + return r; +} + +static void ioreg_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + struct amd_fake_dev *adev = to_adev(info); + + WREG32_IO(reg, val); +} + int atom_bios_init(struct amd_fake_dev *adev) { struct card_info *info = &adev->card_info; @@ -59,8 +116,19 @@ int atom_bios_init(struct amd_fake_dev *adev) info->mc_read = info->pll_read = null_read; info->mc_write = info->pll_write = null_write; - info->reg_read = info->ioreg_read = reg_read; - info->reg_write = info->ioreg_write = reg_write; + info->reg_read = reg_read; + info->reg_write = reg_write; + if (adev_to_amd_private(adev)->rio_mem) + { + info->ioreg_read = ioreg_read; + info->ioreg_write = ioreg_write; + } + else + { + pr_warn("vendor-reset: using MMIO to access I/O\n"); + info->ioreg_read = reg_read; + info->ioreg_write = reg_write; + } adev->atom_context = amdgpu_atom_parse(info, adev->bios); if (!adev->atom_context) diff --git a/src/amd/firmware.h b/src/amd/firmware.h index 10ad0ba..cd0d757 100644 --- a/src/amd/firmware.h +++ b/src/amd/firmware.h @@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #ifndef __VENDOR_RESET_FIRMWARE_H__ #define __VENDOR_RESET_FIRMWARE_H__ +struct amd_fake_dev; int atom_bios_init(struct amd_fake_dev *adev); void atom_bios_fini(struct amd_fake_dev *adev);