Contributors: 18
Author Tokens Token Proportion Commits Commit Proportion
Ville Syrjälä 716 58.88% 15 31.91%
Jani Nikula 332 27.30% 12 25.53%
Simon Richter 47 3.87% 1 2.13%
David Weinehall 25 2.06% 1 2.13%
Thomas Zimmermann 24 1.97% 1 2.13%
Daniele Ceraolo Spurio 20 1.64% 1 2.13%
Chris Wilson 14 1.15% 4 8.51%
Tvrtko A. Ursulin 10 0.82% 1 2.13%
Emil Velikov 8 0.66% 1 2.13%
Uma Shankar 4 0.33% 2 4.26%
Wambui Karuga 4 0.33% 1 2.13%
Michal Wajdeczko 3 0.25% 1 2.13%
Paulo Zanoni 3 0.25% 1 2.13%
Matt Roper 2 0.16% 1 2.13%
Christoph Hellwig 1 0.08% 1 2.13%
Sonika Jindal 1 0.08% 1 2.13%
Ben Gamari 1 0.08% 1 2.13%
Jesse Barnes 1 0.08% 1 2.13%
Total 1216 47


// SPDX-License-Identifier: MIT
/*
 * Copyright © 2019 Intel Corporation
 */

#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/vgaarb.h>

#include <drm/drm_device.h>
#include <drm/drm_print.h>
#include <drm/intel/i915_drm.h>
#include <video/vga.h>

#include "intel_de.h"
#include "intel_display.h"
#include "intel_display_types.h"
#include "intel_vga.h"
#include "intel_vga_regs.h"

static unsigned int intel_gmch_ctrl_reg(struct intel_display *display)
{
	return DISPLAY_VER(display) >= 6 ? SNB_GMCH_CTRL : I830_GMCH_CTRL;
}

static bool intel_vga_decode_is_enabled(struct intel_display *display)
{
	struct pci_dev *pdev = to_pci_dev(display->drm->dev);
	u16 gmch_ctrl = 0;

	if (pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0),
				     intel_gmch_ctrl_reg(display), &gmch_ctrl))
		return false;

	return !(gmch_ctrl & INTEL_GMCH_VGA_DISABLE);
}

static i915_reg_t intel_vga_cntrl_reg(struct intel_display *display)
{
	if (display->platform.valleyview || display->platform.cherryview)
		return VLV_VGACNTRL;
	else if (DISPLAY_VER(display) >= 5)
		return CPU_VGACNTRL;
	else
		return VGACNTRL;
}

static bool has_vga_pipe_sel(struct intel_display *display)
{
	if (display->platform.i845g ||
	    display->platform.i865g)
		return false;

	if (display->platform.valleyview ||
	    display->platform.cherryview)
		return true;

	return DISPLAY_VER(display) < 7;
}

static bool has_vga_mmio_access(struct intel_display *display)
{
	/* WaEnableVGAAccessThroughIOPort:ctg+ */
	return DISPLAY_VER(display) < 5 && !display->platform.g4x;
}

static bool intel_pci_has_vga_io_decode(struct pci_dev *pdev)
{
	u16 cmd = 0;

	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
	if ((cmd & PCI_COMMAND_IO) == 0)
		return false;

	pdev = pdev->bus->self;
	while (pdev) {
		u16 ctl = 0;

		pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &ctl);
		if ((ctl & PCI_BRIDGE_CTL_VGA) == 0)
			return false;

		pdev = pdev->bus->self;
	}

	return true;
}

static bool intel_pci_set_io_decode(struct pci_dev *pdev, bool enable)
{
	u16 old = 0, cmd;

	pci_read_config_word(pdev, PCI_COMMAND, &old);
	cmd = old & ~PCI_COMMAND_IO;
	if (enable)
		cmd |= PCI_COMMAND_IO;
	pci_write_config_word(pdev, PCI_COMMAND, cmd);

	return old & PCI_COMMAND_IO;
}

static bool intel_pci_bridge_set_vga(struct pci_dev *pdev, bool enable)
{
	u16 old = 0, ctl;

	pci_read_config_word(pdev->bus->self, PCI_BRIDGE_CONTROL, &old);
	ctl = old & ~PCI_BRIDGE_CTL_VGA;
	if (enable)
		ctl |= PCI_BRIDGE_CTL_VGA;
	pci_write_config_word(pdev->bus->self, PCI_BRIDGE_CONTROL, ctl);

	return old & PCI_BRIDGE_CTL_VGA;
}

static int intel_vga_get(struct intel_display *display, bool mmio,
			 bool *old_io_decode)
{
	struct pci_dev *pdev = to_pci_dev(display->drm->dev);
	int err;

	if (mmio) {
		*old_io_decode = false;
		return 0;
	}

	/*
	 * Bypass the VGA arbiter on the iGPU and just enable
	 * IO decode by hand. This avoids clobbering the VGA
	 * routing for an external GPU when it's the current
	 * VGA device, and thus prevents the all 0xff/white
	 * readout from VGA memory when taking over from vgacon.
	 *
	 * The iGPU has the highest VGA decode priority so it will
	 * grab any VGA IO access when IO decode is enabled, regardless
	 * of how any other VGA routing bits are configured.
	 */
	if (display->platform.dgfx) {
		err = vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO);
		if (err)
			return err;
	}

	*old_io_decode = intel_pci_set_io_decode(pdev, true);

	return 0;
}

static void intel_vga_put(struct intel_display *display, bool io_decode, bool mmio)
{
	struct pci_dev *pdev = to_pci_dev(display->drm->dev);

	if (mmio)
		return;

	/* see intel_vga_get() */
	intel_pci_set_io_decode(pdev, io_decode);

	if (display->platform.dgfx)
		vga_put(pdev, VGA_RSRC_LEGACY_IO);
}

u8 intel_vga_read(struct intel_display *display, u16 reg, bool mmio)
{
	if (mmio)
		return intel_de_read8(display, _MMIO(reg));
	else
		return inb(reg);
}

static void intel_vga_write(struct intel_display *display, u16 reg, u8 val, bool mmio)
{
	if (mmio)
		intel_de_write8(display, _MMIO(reg), val);
	else
		outb(val, reg);
}

/* Disable the VGA plane that we never use */
void intel_vga_disable(struct intel_display *display)
{
	struct pci_dev *pdev = to_pci_dev(display->drm->dev);
	i915_reg_t vga_reg = intel_vga_cntrl_reg(display);
	bool mmio = has_vga_mmio_access(display);
	bool io_decode;
	u8 msr, sr1;
	u32 tmp;
	int err;

	if (!intel_vga_decode_is_enabled(display)) {
		drm_dbg_kms(display->drm, "VGA decode is disabled\n");

		/*
		 * On older hardware VGA_DISP_DISABLE defaults to 0, but
		 * it *must* be set or else the pipe will be completely
		 * stuck (at least on g4x).
		 */
		goto reset_vgacntr;
	}

	tmp = intel_de_read(display, vga_reg);

	if ((tmp & VGA_DISP_DISABLE) == 0) {
		enum pipe pipe;

		if (display->platform.cherryview)
			pipe = REG_FIELD_GET(VGA_PIPE_SEL_MASK_CHV, tmp);
		else if (has_vga_pipe_sel(display))
			pipe = REG_FIELD_GET(VGA_PIPE_SEL_MASK, tmp);
		else
			pipe = PIPE_A;

		drm_dbg_kms(display->drm, "Disabling VGA plane on pipe %c\n",
			    pipe_name(pipe));
	} else {
		drm_dbg_kms(display->drm, "VGA plane is disabled\n");

		/*
		 * Unfortunately at least some BIOSes (eg. HSW Lenovo
		 * ThinkCentre E73) set up the VGA registers even when
		 * in UEFI mode with the VGA plane disabled. So we need to
		 * always clean up the mess for iGPUs. For discrete GPUs we
		 * don't really care about the state of the VGA registers
		 * since all VGA accesses can be blocked via the bridge.
		 */
		if (display->platform.dgfx)
			goto reset_vgacntr;
	}

	/*
	 * This should not fail, because the vga_get() family of functions
	 * will only report errors for dGPUs that are unreachable via the
	 * bridge, and cannot be made reachable either. We shouldn't even
	 * get here for this case, but if we do, we assume that the bridge
	 * will also refuse future requests to forward VGA accesses.
	 */
	err = intel_vga_get(display, mmio, &io_decode);
	if (err)
		goto reset_vgacntr;

	drm_WARN_ON(display->drm, !mmio && !intel_pci_has_vga_io_decode(pdev));

	intel_vga_write(display, VGA_SEQ_I, 0x01, mmio);
	sr1 = intel_vga_read(display, VGA_SEQ_D, mmio);
	sr1 |= VGA_SR01_SCREEN_OFF;
	intel_vga_write(display, VGA_SEQ_D, sr1, mmio);

	msr = intel_vga_read(display, VGA_MIS_R, mmio);
	/*
	 * Always disable VGA memory decode for iGPU so that
	 * intel_vga_set_decode() doesn't need to access VGA registers.
	 * VGA_MIS_ENB_MEM_ACCESS=0 is also the reset value.
	 */
	msr &= ~VGA_MIS_ENB_MEM_ACCESS;
	/*
	 * VGA_MIS_COLOR controls both GPU level and display engine level
	 * MDA vs. CGA decode logic. But when the register gets reset
	 * (reset value has VGA_MIS_COLOR=0) by the power well, only the
	 * display engine level decode logic gets notified.
	 *
	 * Switch to MDA mode to make sure the GPU level decode logic will
	 * be in sync with the display engine level decode logic after the
	 * power well has been reset. Otherwise the GPU will claim CGA
	 * register accesses but the display engine will not, causing
	 * RMbus NoClaim errors.
	 */
	msr &= ~VGA_MIS_COLOR;
	intel_vga_write(display, VGA_MIS_W, msr, mmio);

	intel_vga_put(display, io_decode, mmio);

	/*
	 * Inform the arbiter about VGA memory decode being disabled so
	 * that it doesn't disable all memory decode for the iGPU when
	 * targeting another GPU.
	 */
	if (!display->platform.dgfx)
		vga_set_legacy_decoding(pdev, VGA_RSRC_LEGACY_IO);

	udelay(300);

reset_vgacntr:
	intel_de_write(display, vga_reg, VGA_DISP_DISABLE);
	intel_de_posting_read(display, vga_reg);
}

static unsigned int intel_vga_set_decode(struct pci_dev *pdev, bool enable_decode)
{
	struct intel_display *display = to_intel_display(pdev);
	unsigned int decodes = VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;

	drm_dbg_kms(display->drm, "%s VGA decode due to VGA arbitration\n",
		    str_enable_disable(enable_decode));

	/*
	 * Can't use GMCH_CTRL INTEL_GMCH_VGA_DISABLE to disable VGA
	 * decode on ILK+ since the register is locked. Instead
	 * intel_disable_vga() will disable VGA memory decode for the
	 * iGPU, and here we just need to take care of the IO decode.
	 * For discrete GPUs we rely on the bridge VGA control.
	 *
	 * We can't disable IO decode already in intel_vga_disable()
	 * because at least some laptops (eg. CTG Dell Latitude E5400)
	 * will hang during reboot/shutfown with IO decode disabled.
	 */
	if (display->platform.dgfx) {
		if (!enable_decode)
			intel_pci_bridge_set_vga(pdev, false);
		else
			decodes |= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
	} else {
		if (!enable_decode)
			intel_pci_set_io_decode(pdev, false);
		else
			decodes |= VGA_RSRC_LEGACY_IO;
	}

	return decodes;
}

void intel_vga_register(struct intel_display *display)
{

	struct pci_dev *pdev = to_pci_dev(display->drm->dev);
	int ret;

	/*
	 * If we have > 1 VGA cards, then we need to arbitrate access to the
	 * common VGA resources.
	 *
	 * If we are a secondary display controller (!PCI_DISPLAY_CLASS_VGA),
	 * then we do not take part in VGA arbitration and the
	 * vga_client_register() fails with -ENODEV.
	 */
	ret = vga_client_register(pdev, intel_vga_set_decode);
	drm_WARN_ON(display->drm, ret && ret != -ENODEV);
}

void intel_vga_unregister(struct intel_display *display)
{
	struct pci_dev *pdev = to_pci_dev(display->drm->dev);

	vga_client_unregister(pdev);
}