freebsd-nq/sys/dev/drm2/i915/intel_acpi.c
Warner Losh 592ffb2175 Revert drm2 removal.
Revert r338177, r338176, r338175, r338174, r338172

After long consultations with re@, core members and mmacy, revert
these changes. Followup changes will be made to mark them as
deprecated and prent a message about where to find the up-to-date
driver.  Followup commits will be made to make this clear in the
installer. Followup commits to reduce POLA in ways we're still
exploring.

It's anticipated that after the freeze, this will be removed in
13-current (with the residual of the drm2 code copied to
sys/arm/dev/drm2 for the TEGRA port's use w/o the intel or
radeon drivers).

Due to the impending freeze, there was no formal core vote for
this. I've been talking to different core members all day, as well as
Matt Macey and Glen Barber. Nobody is completely happy, all are
grudgingly going along with this. Work is in progress to mitigate
the negative effects as much as possible.

Requested by: re@ (gjb, rgrimes)
2018-08-24 00:02:00 +00:00

257 lines
5.8 KiB
C

/*
* Intel ACPI functions
*
* _DSM related code stolen from nouveau_acpi.c.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <dev/drm2/drmP.h>
#include <dev/drm2/i915/i915_drv.h>
#include <contrib/dev/acpica/include/acpi.h>
#include <contrib/dev/acpica/include/accommon.h>
#include <dev/acpica/acpivar.h>
#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */
#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
static struct intel_dsm_priv {
ACPI_HANDLE dhandle;
} intel_dsm_priv;
static const u8 intel_dsm_guid[] = {
0xd3, 0x73, 0xd8, 0x7e,
0xd0, 0xc2,
0x4f, 0x4e,
0xa8, 0x54,
0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
};
static int intel_dsm(ACPI_HANDLE handle, int func, int arg)
{
ACPI_BUFFER output = { ACPI_ALLOCATE_BUFFER, NULL };
ACPI_OBJECT_LIST input;
ACPI_OBJECT params[4];
ACPI_OBJECT *obj;
u32 result;
int ret = 0;
input.Count = 4;
input.Pointer = params;
params[0].Type = ACPI_TYPE_BUFFER;
params[0].Buffer.Length = sizeof(intel_dsm_guid);
params[0].Buffer.Pointer = __DECONST(char *, intel_dsm_guid);
params[1].Type = ACPI_TYPE_INTEGER;
params[1].Integer.Value = INTEL_DSM_REVISION_ID;
params[2].Type = ACPI_TYPE_INTEGER;
params[2].Integer.Value = func;
params[3].Type = ACPI_TYPE_INTEGER;
params[3].Integer.Value = arg;
ret = AcpiEvaluateObject(handle, "_DSM", &input, &output);
if (ret) {
DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
return ret;
}
obj = (ACPI_OBJECT *)output.Pointer;
result = 0;
switch (obj->Type) {
case ACPI_TYPE_INTEGER:
result = obj->Integer.Value;
break;
case ACPI_TYPE_BUFFER:
if (obj->Buffer.Length == 4) {
result = (obj->Buffer.Pointer[0] |
(obj->Buffer.Pointer[1] << 8) |
(obj->Buffer.Pointer[2] << 16) |
(obj->Buffer.Pointer[3] << 24));
break;
}
default:
ret = -EINVAL;
break;
}
if (result == 0x80000002)
ret = -ENODEV;
AcpiOsFree(output.Pointer);
return ret;
}
static char *intel_dsm_port_name(u8 id)
{
switch (id) {
case 0:
return "Reserved";
case 1:
return "Analog VGA";
case 2:
return "LVDS";
case 3:
return "Reserved";
case 4:
return "HDMI/DVI_B";
case 5:
return "HDMI/DVI_C";
case 6:
return "HDMI/DVI_D";
case 7:
return "DisplayPort_A";
case 8:
return "DisplayPort_B";
case 9:
return "DisplayPort_C";
case 0xa:
return "DisplayPort_D";
case 0xb:
case 0xc:
case 0xd:
return "Reserved";
case 0xe:
return "WiDi";
default:
return "bad type";
}
}
static char *intel_dsm_mux_type(u8 type)
{
switch (type) {
case 0:
return "unknown";
case 1:
return "No MUX, iGPU only";
case 2:
return "No MUX, dGPU only";
case 3:
return "MUXed between iGPU and dGPU";
default:
return "bad type";
}
}
static void intel_dsm_platform_mux_info(void)
{
ACPI_BUFFER output = { ACPI_ALLOCATE_BUFFER, NULL };
ACPI_OBJECT_LIST input;
ACPI_OBJECT params[4];
ACPI_OBJECT *pkg;
int i, ret;
input.Count = 4;
input.Pointer = params;
params[0].Type = ACPI_TYPE_BUFFER;
params[0].Buffer.Length = sizeof(intel_dsm_guid);
params[0].Buffer.Pointer = __DECONST(char *, intel_dsm_guid);
params[1].Type = ACPI_TYPE_INTEGER;
params[1].Integer.Value = INTEL_DSM_REVISION_ID;
params[2].Type = ACPI_TYPE_INTEGER;
params[2].Integer.Value = INTEL_DSM_FN_PLATFORM_MUX_INFO;
params[3].Type = ACPI_TYPE_INTEGER;
params[3].Integer.Value = 0;
ret = AcpiEvaluateObject(intel_dsm_priv.dhandle, "_DSM", &input,
&output);
if (ret) {
DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
goto out;
}
pkg = (ACPI_OBJECT *)output.Pointer;
if (pkg->Type == ACPI_TYPE_PACKAGE) {
ACPI_OBJECT *connector_count = &pkg->Package.Elements[0];
DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
(unsigned long long)connector_count->Integer.Value);
for (i = 1; i < pkg->Package.Count; i++) {
ACPI_OBJECT *obj = &pkg->Package.Elements[i];
ACPI_OBJECT *connector_id =
&obj->Package.Elements[0];
ACPI_OBJECT *info = &obj->Package.Elements[1];
DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
(unsigned long long)connector_id->Integer.Value);
DRM_DEBUG_DRIVER(" port id: %s\n",
intel_dsm_port_name(info->Buffer.Pointer[0]));
DRM_DEBUG_DRIVER(" display mux info: %s\n",
intel_dsm_mux_type(info->Buffer.Pointer[1]));
DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n",
intel_dsm_mux_type(info->Buffer.Pointer[2]));
DRM_DEBUG_DRIVER(" hpd mux info: %s\n",
intel_dsm_mux_type(info->Buffer.Pointer[3]));
}
}
out:
AcpiOsFree(output.Pointer);
}
static bool intel_dsm_pci_probe(device_t dev)
{
ACPI_HANDLE dhandle, intel_handle;
ACPI_STATUS status;
int ret;
dhandle = acpi_get_handle(dev);
if (!dhandle)
return false;
status = AcpiGetHandle(dhandle, "_DSM", &intel_handle);
if (ACPI_FAILURE(status)) {
DRM_DEBUG_KMS("no _DSM method for intel device\n");
return false;
}
ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
if (ret < 0) {
DRM_DEBUG_KMS("failed to get supported _DSM functions\n");
return false;
}
intel_dsm_priv.dhandle = dhandle;
intel_dsm_platform_mux_info();
return true;
}
static bool intel_dsm_detect(void)
{
char acpi_method_name[255] = { 0 };
ACPI_BUFFER buffer = {sizeof(acpi_method_name), acpi_method_name};
device_t dev = NULL;
bool has_dsm = false;
int vga_count = 0;
#ifdef FREEBSD_WIP
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
#endif /* FREEBSD_WIP */
if ((dev = pci_find_class(PCIC_DISPLAY, PCIS_DISPLAY_VGA)) != NULL) {
vga_count++;
has_dsm |= intel_dsm_pci_probe(dev);
}
if (vga_count == 2 && has_dsm) {
AcpiGetName(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
acpi_method_name);
return true;
}
return false;
}
void intel_register_dsm_handler(void)
{
if (!intel_dsm_detect())
return;
}
void intel_unregister_dsm_handler(void)
{
}