1a13144e2SJani Nikula // SPDX-License-Identifier: MIT 2a13144e2SJani Nikula /* 3a13144e2SJani Nikula * Copyright © 2023 Intel Corporation 4a13144e2SJani Nikula */ 5a13144e2SJani Nikula 6a13144e2SJani Nikula #include <linux/pci.h> 7a13144e2SJani Nikula #include <linux/pnp.h> 8*5846cdfdSUma Shankar #include <linux/vgaarb.h> 9a13144e2SJani Nikula 10a13144e2SJani Nikula #include <drm/drm_managed.h> 11eee838e4SJani Nikula #include <drm/i915_drm.h> 12a13144e2SJani Nikula 13a13144e2SJani Nikula #include "i915_drv.h" 14a13144e2SJani Nikula #include "intel_gmch.h" 15a13144e2SJani Nikula #include "intel_pci_config.h" 16a13144e2SJani Nikula 17a13144e2SJani Nikula static void intel_gmch_bridge_release(struct drm_device *dev, void *bridge) 18a13144e2SJani Nikula { 19a13144e2SJani Nikula pci_dev_put(bridge); 20a13144e2SJani Nikula } 21a13144e2SJani Nikula 22b1e7d8b0SJani Nikula int intel_gmch_bridge_setup(struct drm_i915_private *i915) 23a13144e2SJani Nikula { 24b1e7d8b0SJani Nikula int domain = pci_domain_nr(to_pci_dev(i915->drm.dev)->bus); 25a13144e2SJani Nikula 26b1e7d8b0SJani Nikula i915->gmch.pdev = pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(0, 0)); 27b1e7d8b0SJani Nikula if (!i915->gmch.pdev) { 28b1e7d8b0SJani Nikula drm_err(&i915->drm, "bridge device not found\n"); 29a13144e2SJani Nikula return -EIO; 30a13144e2SJani Nikula } 31a13144e2SJani Nikula 32b1e7d8b0SJani Nikula return drmm_add_action_or_reset(&i915->drm, intel_gmch_bridge_release, 33b1e7d8b0SJani Nikula i915->gmch.pdev); 34a13144e2SJani Nikula } 35a13144e2SJani Nikula 36a13144e2SJani Nikula /* Allocate space for the MCH regs if needed, return nonzero on error */ 37a13144e2SJani Nikula static int 38b1e7d8b0SJani Nikula intel_alloc_mchbar_resource(struct drm_i915_private *i915) 39a13144e2SJani Nikula { 40b1e7d8b0SJani Nikula int reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915; 41a13144e2SJani Nikula u32 temp_lo, temp_hi = 0; 42a13144e2SJani Nikula u64 mchbar_addr; 43a13144e2SJani Nikula int ret; 44a13144e2SJani Nikula 45b1e7d8b0SJani Nikula if (GRAPHICS_VER(i915) >= 4) 46b1e7d8b0SJani Nikula pci_read_config_dword(i915->gmch.pdev, reg + 4, &temp_hi); 47b1e7d8b0SJani Nikula pci_read_config_dword(i915->gmch.pdev, reg, &temp_lo); 48a13144e2SJani Nikula mchbar_addr = ((u64)temp_hi << 32) | temp_lo; 49a13144e2SJani Nikula 50a13144e2SJani Nikula /* If ACPI doesn't have it, assume we need to allocate it ourselves */ 51b02a9a0cSArnd Bergmann if (IS_ENABLED(CONFIG_PNP) && mchbar_addr && 52a13144e2SJani Nikula pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) 53a13144e2SJani Nikula return 0; 54a13144e2SJani Nikula 55a13144e2SJani Nikula /* Get some space for it */ 56b1e7d8b0SJani Nikula i915->gmch.mch_res.name = "i915 MCHBAR"; 57b1e7d8b0SJani Nikula i915->gmch.mch_res.flags = IORESOURCE_MEM; 58b1e7d8b0SJani Nikula ret = pci_bus_alloc_resource(i915->gmch.pdev->bus, 59b1e7d8b0SJani Nikula &i915->gmch.mch_res, 60a13144e2SJani Nikula MCHBAR_SIZE, MCHBAR_SIZE, 61a13144e2SJani Nikula PCIBIOS_MIN_MEM, 62a13144e2SJani Nikula 0, pcibios_align_resource, 63b1e7d8b0SJani Nikula i915->gmch.pdev); 64a13144e2SJani Nikula if (ret) { 65b1e7d8b0SJani Nikula drm_dbg(&i915->drm, "failed bus alloc: %d\n", ret); 66b1e7d8b0SJani Nikula i915->gmch.mch_res.start = 0; 67a13144e2SJani Nikula return ret; 68a13144e2SJani Nikula } 69a13144e2SJani Nikula 70b1e7d8b0SJani Nikula if (GRAPHICS_VER(i915) >= 4) 71b1e7d8b0SJani Nikula pci_write_config_dword(i915->gmch.pdev, reg + 4, 72b1e7d8b0SJani Nikula upper_32_bits(i915->gmch.mch_res.start)); 73a13144e2SJani Nikula 74b1e7d8b0SJani Nikula pci_write_config_dword(i915->gmch.pdev, reg, 75b1e7d8b0SJani Nikula lower_32_bits(i915->gmch.mch_res.start)); 76a13144e2SJani Nikula return 0; 77a13144e2SJani Nikula } 78a13144e2SJani Nikula 79a13144e2SJani Nikula /* Setup MCHBAR if possible, return true if we should disable it again */ 80b1e7d8b0SJani Nikula void intel_gmch_bar_setup(struct drm_i915_private *i915) 81a13144e2SJani Nikula { 82b1e7d8b0SJani Nikula int mchbar_reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915; 83a13144e2SJani Nikula u32 temp; 84a13144e2SJani Nikula bool enabled; 85a13144e2SJani Nikula 86b1e7d8b0SJani Nikula if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) 87a13144e2SJani Nikula return; 88a13144e2SJani Nikula 89b1e7d8b0SJani Nikula i915->gmch.mchbar_need_disable = false; 90a13144e2SJani Nikula 91b1e7d8b0SJani Nikula if (IS_I915G(i915) || IS_I915GM(i915)) { 92b1e7d8b0SJani Nikula pci_read_config_dword(i915->gmch.pdev, DEVEN, &temp); 93a13144e2SJani Nikula enabled = !!(temp & DEVEN_MCHBAR_EN); 94a13144e2SJani Nikula } else { 95b1e7d8b0SJani Nikula pci_read_config_dword(i915->gmch.pdev, mchbar_reg, &temp); 96a13144e2SJani Nikula enabled = temp & 1; 97a13144e2SJani Nikula } 98a13144e2SJani Nikula 99a13144e2SJani Nikula /* If it's already enabled, don't have to do anything */ 100a13144e2SJani Nikula if (enabled) 101a13144e2SJani Nikula return; 102a13144e2SJani Nikula 103b1e7d8b0SJani Nikula if (intel_alloc_mchbar_resource(i915)) 104a13144e2SJani Nikula return; 105a13144e2SJani Nikula 106b1e7d8b0SJani Nikula i915->gmch.mchbar_need_disable = true; 107a13144e2SJani Nikula 108a13144e2SJani Nikula /* Space is allocated or reserved, so enable it. */ 109b1e7d8b0SJani Nikula if (IS_I915G(i915) || IS_I915GM(i915)) { 110b1e7d8b0SJani Nikula pci_write_config_dword(i915->gmch.pdev, DEVEN, 111a13144e2SJani Nikula temp | DEVEN_MCHBAR_EN); 112a13144e2SJani Nikula } else { 113b1e7d8b0SJani Nikula pci_read_config_dword(i915->gmch.pdev, mchbar_reg, &temp); 114b1e7d8b0SJani Nikula pci_write_config_dword(i915->gmch.pdev, mchbar_reg, temp | 1); 115a13144e2SJani Nikula } 116a13144e2SJani Nikula } 117a13144e2SJani Nikula 118b1e7d8b0SJani Nikula void intel_gmch_bar_teardown(struct drm_i915_private *i915) 119a13144e2SJani Nikula { 120b1e7d8b0SJani Nikula int mchbar_reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915; 121a13144e2SJani Nikula 122b1e7d8b0SJani Nikula if (i915->gmch.mchbar_need_disable) { 123b1e7d8b0SJani Nikula if (IS_I915G(i915) || IS_I915GM(i915)) { 124a13144e2SJani Nikula u32 deven_val; 125a13144e2SJani Nikula 126b1e7d8b0SJani Nikula pci_read_config_dword(i915->gmch.pdev, DEVEN, 127a13144e2SJani Nikula &deven_val); 128a13144e2SJani Nikula deven_val &= ~DEVEN_MCHBAR_EN; 129b1e7d8b0SJani Nikula pci_write_config_dword(i915->gmch.pdev, DEVEN, 130a13144e2SJani Nikula deven_val); 131a13144e2SJani Nikula } else { 132a13144e2SJani Nikula u32 mchbar_val; 133a13144e2SJani Nikula 134b1e7d8b0SJani Nikula pci_read_config_dword(i915->gmch.pdev, mchbar_reg, 135a13144e2SJani Nikula &mchbar_val); 136a13144e2SJani Nikula mchbar_val &= ~1; 137b1e7d8b0SJani Nikula pci_write_config_dword(i915->gmch.pdev, mchbar_reg, 138a13144e2SJani Nikula mchbar_val); 139a13144e2SJani Nikula } 140a13144e2SJani Nikula } 141a13144e2SJani Nikula 142b1e7d8b0SJani Nikula if (i915->gmch.mch_res.start) 143b1e7d8b0SJani Nikula release_resource(&i915->gmch.mch_res); 144a13144e2SJani Nikula } 145eee838e4SJani Nikula 146eee838e4SJani Nikula int intel_gmch_vga_set_state(struct drm_i915_private *i915, bool enable_decode) 147eee838e4SJani Nikula { 148eee838e4SJani Nikula unsigned int reg = DISPLAY_VER(i915) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL; 149eee838e4SJani Nikula u16 gmch_ctrl; 150eee838e4SJani Nikula 151eee838e4SJani Nikula if (pci_read_config_word(i915->gmch.pdev, reg, &gmch_ctrl)) { 152eee838e4SJani Nikula drm_err(&i915->drm, "failed to read control word\n"); 153eee838e4SJani Nikula return -EIO; 154eee838e4SJani Nikula } 155eee838e4SJani Nikula 156eee838e4SJani Nikula if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !enable_decode) 157eee838e4SJani Nikula return 0; 158eee838e4SJani Nikula 159eee838e4SJani Nikula if (enable_decode) 160eee838e4SJani Nikula gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE; 161eee838e4SJani Nikula else 162eee838e4SJani Nikula gmch_ctrl |= INTEL_GMCH_VGA_DISABLE; 163eee838e4SJani Nikula 164eee838e4SJani Nikula if (pci_write_config_word(i915->gmch.pdev, reg, gmch_ctrl)) { 165eee838e4SJani Nikula drm_err(&i915->drm, "failed to write control word\n"); 166eee838e4SJani Nikula return -EIO; 167eee838e4SJani Nikula } 168eee838e4SJani Nikula 169eee838e4SJani Nikula return 0; 170eee838e4SJani Nikula } 171*5846cdfdSUma Shankar 172*5846cdfdSUma Shankar unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_decode) 173*5846cdfdSUma Shankar { 174*5846cdfdSUma Shankar struct drm_i915_private *i915 = pdev_to_i915(pdev); 175*5846cdfdSUma Shankar 176*5846cdfdSUma Shankar intel_gmch_vga_set_state(i915, enable_decode); 177*5846cdfdSUma Shankar 178*5846cdfdSUma Shankar if (enable_decode) 179*5846cdfdSUma Shankar return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | 180*5846cdfdSUma Shankar VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 181*5846cdfdSUma Shankar else 182*5846cdfdSUma Shankar return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 183*5846cdfdSUma Shankar } 184