summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_vga.c
blob: 4c292fae7b92142425d2b404f527890f42091610 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
// 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 intel_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);
	intel_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(void *data, bool enable_decode)
{
	struct intel_display *display = data;
	struct pci_dev *pdev = to_pci_dev(display->drm->dev);
	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, display);
	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);
}