| 1 | // SPDX-License-Identifier: MIT | 
|---|
| 2 | /* | 
|---|
| 3 | * Copyright © 2019 Intel Corporation | 
|---|
| 4 | */ | 
|---|
| 5 |  | 
|---|
| 6 | #include <linux/delay.h> | 
|---|
| 7 | #include <linux/pci.h> | 
|---|
| 8 | #include <linux/vgaarb.h> | 
|---|
| 9 |  | 
|---|
| 10 | #include <drm/drm_device.h> | 
|---|
| 11 | #include <drm/drm_print.h> | 
|---|
| 12 | #include <video/vga.h> | 
|---|
| 13 |  | 
|---|
| 14 | #include "soc/intel_gmch.h" | 
|---|
| 15 |  | 
|---|
| 16 | #include "intel_de.h" | 
|---|
| 17 | #include "intel_display.h" | 
|---|
| 18 | #include "intel_vga.h" | 
|---|
| 19 | #include "intel_vga_regs.h" | 
|---|
| 20 |  | 
|---|
| 21 | static i915_reg_t intel_vga_cntrl_reg(struct intel_display *display) | 
|---|
| 22 | { | 
|---|
| 23 | if (display->platform.valleyview || display->platform.cherryview) | 
|---|
| 24 | return VLV_VGACNTRL; | 
|---|
| 25 | else if (DISPLAY_VER(display) >= 5) | 
|---|
| 26 | return CPU_VGACNTRL; | 
|---|
| 27 | else | 
|---|
| 28 | return VGACNTRL; | 
|---|
| 29 | } | 
|---|
| 30 |  | 
|---|
| 31 | static bool has_vga_pipe_sel(struct intel_display *display) | 
|---|
| 32 | { | 
|---|
| 33 | if (display->platform.i845g || | 
|---|
| 34 | display->platform.i865g) | 
|---|
| 35 | return false; | 
|---|
| 36 |  | 
|---|
| 37 | if (display->platform.valleyview || | 
|---|
| 38 | display->platform.cherryview) | 
|---|
| 39 | return true; | 
|---|
| 40 |  | 
|---|
| 41 | return DISPLAY_VER(display) < 7; | 
|---|
| 42 | } | 
|---|
| 43 |  | 
|---|
| 44 | /* Disable the VGA plane that we never use */ | 
|---|
| 45 | void intel_vga_disable(struct intel_display *display) | 
|---|
| 46 | { | 
|---|
| 47 | struct pci_dev *pdev = to_pci_dev(display->drm->dev); | 
|---|
| 48 | i915_reg_t vga_reg = intel_vga_cntrl_reg(display); | 
|---|
| 49 | enum pipe pipe; | 
|---|
| 50 | u32 tmp; | 
|---|
| 51 | u8 sr1; | 
|---|
| 52 |  | 
|---|
| 53 | tmp = intel_de_read(display, reg: vga_reg); | 
|---|
| 54 | if (tmp & VGA_DISP_DISABLE) | 
|---|
| 55 | return; | 
|---|
| 56 |  | 
|---|
| 57 | if (display->platform.cherryview) | 
|---|
| 58 | pipe = REG_FIELD_GET(VGA_PIPE_SEL_MASK_CHV, tmp); | 
|---|
| 59 | else if (has_vga_pipe_sel(display)) | 
|---|
| 60 | pipe = REG_FIELD_GET(VGA_PIPE_SEL_MASK, tmp); | 
|---|
| 61 | else | 
|---|
| 62 | pipe = PIPE_A; | 
|---|
| 63 |  | 
|---|
| 64 | drm_dbg_kms(display->drm, "Disabling VGA plane on pipe %c\n", | 
|---|
| 65 | pipe_name(pipe)); | 
|---|
| 66 |  | 
|---|
| 67 | /* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */ | 
|---|
| 68 | vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO); | 
|---|
| 69 | outb(value: 0x01, VGA_SEQ_I); | 
|---|
| 70 | sr1 = inb(VGA_SEQ_D); | 
|---|
| 71 | outb(value: sr1 | VGA_SR01_SCREEN_OFF, VGA_SEQ_D); | 
|---|
| 72 | vga_put(pdev, VGA_RSRC_LEGACY_IO); | 
|---|
| 73 | udelay(usec: 300); | 
|---|
| 74 |  | 
|---|
| 75 | intel_de_write(display, reg: vga_reg, VGA_DISP_DISABLE); | 
|---|
| 76 | intel_de_posting_read(display, reg: vga_reg); | 
|---|
| 77 | } | 
|---|
| 78 |  | 
|---|
| 79 | void intel_vga_reset_io_mem(struct intel_display *display) | 
|---|
| 80 | { | 
|---|
| 81 | struct pci_dev *pdev = to_pci_dev(display->drm->dev); | 
|---|
| 82 |  | 
|---|
| 83 | /* | 
|---|
| 84 | * After we re-enable the power well, if we touch VGA register 0x3d5 | 
|---|
| 85 | * we'll get unclaimed register interrupts. This stops after we write | 
|---|
| 86 | * anything to the VGA MSR register. The vgacon module uses this | 
|---|
| 87 | * register all the time, so if we unbind our driver and, as a | 
|---|
| 88 | * consequence, bind vgacon, we'll get stuck in an infinite loop at | 
|---|
| 89 | * console_unlock(). So make here we touch the VGA MSR register, making | 
|---|
| 90 | * sure vgacon can keep working normally without triggering interrupts | 
|---|
| 91 | * and error messages. | 
|---|
| 92 | */ | 
|---|
| 93 | vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO); | 
|---|
| 94 | outb(inb(VGA_MIS_R), VGA_MIS_W); | 
|---|
| 95 | vga_put(pdev, VGA_RSRC_LEGACY_IO); | 
|---|
| 96 | } | 
|---|
| 97 |  | 
|---|
| 98 | int intel_vga_register(struct intel_display *display) | 
|---|
| 99 | { | 
|---|
| 100 |  | 
|---|
| 101 | struct pci_dev *pdev = to_pci_dev(display->drm->dev); | 
|---|
| 102 | int ret; | 
|---|
| 103 |  | 
|---|
| 104 | /* | 
|---|
| 105 | * If we have > 1 VGA cards, then we need to arbitrate access to the | 
|---|
| 106 | * common VGA resources. | 
|---|
| 107 | * | 
|---|
| 108 | * If we are a secondary display controller (!PCI_DISPLAY_CLASS_VGA), | 
|---|
| 109 | * then we do not take part in VGA arbitration and the | 
|---|
| 110 | * vga_client_register() fails with -ENODEV. | 
|---|
| 111 | */ | 
|---|
| 112 | ret = vga_client_register(pdev, set_decode: intel_gmch_vga_set_decode); | 
|---|
| 113 | if (ret && ret != -ENODEV) | 
|---|
| 114 | return ret; | 
|---|
| 115 |  | 
|---|
| 116 | return 0; | 
|---|
| 117 | } | 
|---|
| 118 |  | 
|---|
| 119 | void intel_vga_unregister(struct intel_display *display) | 
|---|
| 120 | { | 
|---|
| 121 | struct pci_dev *pdev = to_pci_dev(display->drm->dev); | 
|---|
| 122 |  | 
|---|
| 123 | vga_client_unregister(pdev); | 
|---|
| 124 | } | 
|---|
| 125 |  | 
|---|