502 lines
14 KiB
C
502 lines
14 KiB
C
/*
|
|
* Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
|
|
* All Rights Reserved.
|
|
* Copyright © 2010 Intel Corporation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <xf86_OSproc.h>
|
|
#include <xf86Parser.h>
|
|
#include <xf86drmMode.h>
|
|
|
|
#include <xorgVersion.h>
|
|
|
|
#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,6,99,0,0)
|
|
#include <xf86Resources.h>
|
|
#endif
|
|
|
|
#include "common.h"
|
|
#include "intel_driver.h"
|
|
#include "intel_options.h"
|
|
#include "legacy/legacy.h"
|
|
#include "sna/sna_module.h"
|
|
|
|
static struct intel_device_info *chipset_info;
|
|
|
|
static const struct intel_device_info intel_generic_info = {
|
|
.gen = -1,
|
|
};
|
|
|
|
static const struct intel_device_info intel_i81x_info = {
|
|
.gen = 10,
|
|
};
|
|
|
|
static const struct intel_device_info intel_i830_info = {
|
|
.gen = 20,
|
|
};
|
|
static const struct intel_device_info intel_i845_info = {
|
|
.gen = 20,
|
|
};
|
|
static const struct intel_device_info intel_i855_info = {
|
|
.gen = 21,
|
|
};
|
|
static const struct intel_device_info intel_i865_info = {
|
|
.gen = 22,
|
|
};
|
|
|
|
static const struct intel_device_info intel_i915_info = {
|
|
.gen = 30,
|
|
};
|
|
static const struct intel_device_info intel_i945_info = {
|
|
.gen = 31,
|
|
};
|
|
|
|
static const struct intel_device_info intel_g33_info = {
|
|
.gen = 33,
|
|
};
|
|
|
|
static const struct intel_device_info intel_i965_info = {
|
|
.gen = 40,
|
|
};
|
|
|
|
static const struct intel_device_info intel_g4x_info = {
|
|
.gen = 45,
|
|
};
|
|
|
|
static const struct intel_device_info intel_ironlake_info = {
|
|
.gen = 50,
|
|
};
|
|
|
|
static const struct intel_device_info intel_sandybridge_info = {
|
|
.gen = 60,
|
|
};
|
|
|
|
static const struct intel_device_info intel_ivybridge_info = {
|
|
.gen = 70,
|
|
};
|
|
|
|
static const SymTabRec _intel_chipsets[] = {
|
|
{PCI_CHIP_I810, "i810"},
|
|
{PCI_CHIP_I810_DC100, "i810-dc100"},
|
|
{PCI_CHIP_I810_E, "i810e"},
|
|
{PCI_CHIP_I815, "i815"},
|
|
{PCI_CHIP_I830_M, "i830M"},
|
|
{PCI_CHIP_845_G, "845G"},
|
|
{PCI_CHIP_I854, "854"},
|
|
{PCI_CHIP_I855_GM, "852GM/855GM"},
|
|
{PCI_CHIP_I865_G, "865G"},
|
|
{PCI_CHIP_I915_G, "915G"},
|
|
{PCI_CHIP_E7221_G, "E7221 (i915)"},
|
|
{PCI_CHIP_I915_GM, "915GM"},
|
|
{PCI_CHIP_I945_G, "945G"},
|
|
{PCI_CHIP_I945_GM, "945GM"},
|
|
{PCI_CHIP_I945_GME, "945GME"},
|
|
{PCI_CHIP_PINEVIEW_M, "Pineview GM"},
|
|
{PCI_CHIP_PINEVIEW_G, "Pineview G"},
|
|
{PCI_CHIP_I965_G, "965G"},
|
|
{PCI_CHIP_G35_G, "G35"},
|
|
{PCI_CHIP_I965_Q, "965Q"},
|
|
{PCI_CHIP_I946_GZ, "946GZ"},
|
|
{PCI_CHIP_I965_GM, "965GM"},
|
|
{PCI_CHIP_I965_GME, "965GME/GLE"},
|
|
{PCI_CHIP_G33_G, "G33"},
|
|
{PCI_CHIP_Q35_G, "Q35"},
|
|
{PCI_CHIP_Q33_G, "Q33"},
|
|
{PCI_CHIP_GM45_GM, "GM45"},
|
|
{PCI_CHIP_G45_E_G, "4 Series"},
|
|
{PCI_CHIP_G45_G, "G45/G43"},
|
|
{PCI_CHIP_Q45_G, "Q45/Q43"},
|
|
{PCI_CHIP_G41_G, "G41"},
|
|
{PCI_CHIP_B43_G, "B43"},
|
|
{PCI_CHIP_B43_G1, "B43"},
|
|
{PCI_CHIP_IRONLAKE_D_G, "Clarkdale"},
|
|
{PCI_CHIP_IRONLAKE_M_G, "Arrandale"},
|
|
{PCI_CHIP_SANDYBRIDGE_GT1, "Sandybridge Desktop (GT1)" },
|
|
{PCI_CHIP_SANDYBRIDGE_GT2, "Sandybridge Desktop (GT2)" },
|
|
{PCI_CHIP_SANDYBRIDGE_GT2_PLUS, "Sandybridge Desktop (GT2+)" },
|
|
{PCI_CHIP_SANDYBRIDGE_M_GT1, "Sandybridge Mobile (GT1)" },
|
|
{PCI_CHIP_SANDYBRIDGE_M_GT2, "Sandybridge Mobile (GT2)" },
|
|
{PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS, "Sandybridge Mobile (GT2+)" },
|
|
{PCI_CHIP_SANDYBRIDGE_S_GT, "Sandybridge Server" },
|
|
{PCI_CHIP_IVYBRIDGE_M_GT1, "Ivybridge Mobile (GT1)" },
|
|
{PCI_CHIP_IVYBRIDGE_M_GT2, "Ivybridge Mobile (GT2)" },
|
|
{PCI_CHIP_IVYBRIDGE_D_GT1, "Ivybridge Desktop (GT1)" },
|
|
{PCI_CHIP_IVYBRIDGE_D_GT2, "Ivybridge Desktop (GT2)" },
|
|
{PCI_CHIP_IVYBRIDGE_S_GT1, "Ivybridge Server" },
|
|
{PCI_CHIP_IVYBRIDGE_S_GT2, "Ivybridge Server (GT2)" },
|
|
{-1, NULL}
|
|
};
|
|
#define NUM_CHIPSETS (sizeof(_intel_chipsets) / sizeof(_intel_chipsets[0]))
|
|
|
|
SymTabRec *intel_chipsets = (SymTabRec *) _intel_chipsets;
|
|
|
|
#define INTEL_DEVICE_MATCH(d,i) \
|
|
{ 0x8086, (d), PCI_MATCH_ANY, PCI_MATCH_ANY, 0x3 << 16, 0xff << 16, (intptr_t)(i) }
|
|
|
|
static const struct pci_id_match intel_device_match[] = {
|
|
#if !KMS_ONLY
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I810, &intel_i81x_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I810_DC100, &intel_i81x_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I810_E, &intel_i81x_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I815, &intel_i81x_info ),
|
|
#endif
|
|
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I830_M, &intel_i830_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_845_G, &intel_i845_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I854, &intel_i855_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I855_GM, &intel_i855_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I865_G, &intel_i865_info ),
|
|
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I915_G, &intel_i915_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_E7221_G, &intel_i915_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I915_GM, &intel_i915_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I945_G, &intel_i945_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I945_GM, &intel_i945_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I945_GME, &intel_i945_info ),
|
|
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_PINEVIEW_M, &intel_g33_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_PINEVIEW_G, &intel_g33_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_G33_G, &intel_g33_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_Q33_G, &intel_g33_info ),
|
|
/* Another marketing win: Q35 is another g33 device not a gen4 part
|
|
* like its G35 brethren.
|
|
*/
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_Q35_G, &intel_g33_info ),
|
|
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I965_G, &intel_i965_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_G35_G, &intel_i965_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I965_Q, &intel_i965_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I946_GZ, &intel_i965_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I965_GM, &intel_i965_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_I965_GME, &intel_i965_info ),
|
|
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_GM45_GM, &intel_g4x_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_G45_E_G, &intel_g4x_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_G45_G, &intel_g4x_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_Q45_G, &intel_g4x_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_G41_G, &intel_g4x_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_B43_G, &intel_g4x_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_B43_G1, &intel_g4x_info ),
|
|
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_IRONLAKE_D_G, &intel_ironlake_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_IRONLAKE_M_G, &intel_ironlake_info ),
|
|
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_SANDYBRIDGE_GT1, &intel_sandybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_SANDYBRIDGE_GT2, &intel_sandybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_SANDYBRIDGE_GT2_PLUS, &intel_sandybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_SANDYBRIDGE_M_GT1, &intel_sandybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_SANDYBRIDGE_M_GT2, &intel_sandybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS, &intel_sandybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_SANDYBRIDGE_S_GT, &intel_sandybridge_info ),
|
|
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_IVYBRIDGE_M_GT1, &intel_ivybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_IVYBRIDGE_M_GT2, &intel_ivybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_IVYBRIDGE_D_GT1, &intel_ivybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_IVYBRIDGE_D_GT2, &intel_ivybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_IVYBRIDGE_S_GT1, &intel_ivybridge_info ),
|
|
INTEL_DEVICE_MATCH (PCI_CHIP_IVYBRIDGE_S_GT2, &intel_ivybridge_info ),
|
|
|
|
INTEL_DEVICE_MATCH (PCI_MATCH_ANY, &intel_generic_info ),
|
|
{ 0, 0, 0 },
|
|
};
|
|
|
|
const struct intel_device_info *
|
|
intel_detect_chipset(ScrnInfoPtr scrn,
|
|
EntityInfoPtr ent, struct pci_device *pci)
|
|
{
|
|
MessageType from = X_PROBED;
|
|
const char *name = NULL;
|
|
int i;
|
|
|
|
if (ent->device->chipID >= 0) {
|
|
xf86DrvMsg(scrn->scrnIndex, from = X_CONFIG,
|
|
"ChipID override: 0x%04X\n",
|
|
ent->device->chipID);
|
|
DEVICE_ID(pci) = ent->device->chipID;
|
|
}
|
|
|
|
for (i = 0; intel_chipsets[i].name != NULL; i++) {
|
|
if (DEVICE_ID(pci) == intel_chipsets[i].token) {
|
|
name = intel_chipsets[i].name;
|
|
break;
|
|
}
|
|
}
|
|
if (name == NULL) {
|
|
xf86DrvMsg(scrn->scrnIndex, X_WARNING, "unknown chipset\n");
|
|
name = "unknown";
|
|
} else {
|
|
xf86DrvMsg(scrn->scrnIndex, from,
|
|
"Integrated Graphics Chipset: Intel(R) %s\n",
|
|
name);
|
|
}
|
|
|
|
scrn->chipset = name;
|
|
return chipset_info;
|
|
}
|
|
|
|
/*
|
|
* intel_identify --
|
|
*
|
|
* Returns the string name for the driver based on the chipset.
|
|
*
|
|
*/
|
|
static void intel_identify(int flags)
|
|
{
|
|
xf86PrintChipsets(INTEL_NAME,
|
|
"Driver for Intel Integrated Graphics Chipsets",
|
|
intel_chipsets);
|
|
}
|
|
|
|
static Bool intel_driver_func(ScrnInfoPtr pScrn,
|
|
xorgDriverFuncOp op,
|
|
pointer ptr)
|
|
{
|
|
xorgHWFlags *flag;
|
|
|
|
switch (op) {
|
|
case GET_REQUIRED_HW_INTERFACES:
|
|
flag = (CARD32*)ptr;
|
|
#ifdef KMS_ONLY
|
|
(*flag) = 0;
|
|
#else
|
|
(*flag) = HW_IO | HW_MMIO;
|
|
#endif
|
|
return TRUE;
|
|
default:
|
|
/* Unknown or deprecated function */
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static Bool has_kernel_mode_setting(struct pci_device *dev)
|
|
{
|
|
char id[20];
|
|
int ret;
|
|
|
|
snprintf(id, sizeof(id),
|
|
"pci:%04x:%02x:%02x.%d",
|
|
dev->domain, dev->bus, dev->dev, dev->func);
|
|
|
|
ret = drmCheckModesettingSupported(id);
|
|
if (ret && xf86LoadKernelModule("i915"))
|
|
ret = drmCheckModesettingSupported(id);
|
|
/* Be nice to the user and load fbcon too */
|
|
if (!ret)
|
|
(void)xf86LoadKernelModule("fbcon");
|
|
|
|
return ret == 0;
|
|
}
|
|
|
|
extern XF86ConfigPtr xf86configptr;
|
|
|
|
static XF86ConfDevicePtr
|
|
_xf86findDriver(const char *ident, XF86ConfDevicePtr p)
|
|
{
|
|
while (p) {
|
|
if (p->dev_driver && xf86nameCompare(ident, p->dev_driver) == 0)
|
|
return p;
|
|
|
|
p = p->list.next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static enum accel_method { UXA, SNA } get_accel_method(void)
|
|
{
|
|
enum accel_method accel_method = DEFAULT_ACCEL_METHOD;
|
|
XF86ConfDevicePtr dev;
|
|
|
|
dev = _xf86findDriver("intel", xf86configptr->conf_device_lst);
|
|
if (dev && dev->dev_option_lst) {
|
|
const char *s;
|
|
|
|
s = xf86FindOptionValue(dev->dev_option_lst, "AccelMethod");
|
|
if (s ) {
|
|
if (strcasecmp(s, "sna") == 0)
|
|
accel_method = SNA;
|
|
else if (strcasecmp(s, "uxa") == 0)
|
|
accel_method = UXA;
|
|
else if (strcasecmp(s, "glamor") == 0)
|
|
accel_method = UXA;
|
|
}
|
|
}
|
|
|
|
return accel_method;
|
|
}
|
|
|
|
/*
|
|
* intel_pci_probe --
|
|
*
|
|
* Look through the PCI bus to find cards that are intel boards.
|
|
* Setup the dispatch table for the rest of the driver functions.
|
|
*
|
|
*/
|
|
static Bool intel_pci_probe(DriverPtr driver,
|
|
int entity_num,
|
|
struct pci_device *device,
|
|
intptr_t match_data)
|
|
{
|
|
ScrnInfoPtr scrn;
|
|
PciChipsets intel_pci_chipsets[NUM_CHIPSETS];
|
|
unsigned i;
|
|
|
|
chipset_info = (void *)match_data;
|
|
|
|
if (!has_kernel_mode_setting(device)) {
|
|
#if KMS_ONLY
|
|
return FALSE;
|
|
#else
|
|
switch (DEVICE_ID(device)) {
|
|
case PCI_CHIP_I810:
|
|
case PCI_CHIP_I810_DC100:
|
|
case PCI_CHIP_I810_E:
|
|
case PCI_CHIP_I815:
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
for (i = 0; i < NUM_CHIPSETS; i++) {
|
|
intel_pci_chipsets[i].numChipset = intel_chipsets[i].token;
|
|
intel_pci_chipsets[i].PCIid = intel_chipsets[i].token;
|
|
#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,6,99,0,0)
|
|
intel_pci_chipsets[i].resList = RES_SHARED_VGA;
|
|
#else
|
|
intel_pci_chipsets[i].dummy = NULL;
|
|
#endif
|
|
}
|
|
|
|
scrn = xf86ConfigPciEntity(NULL, 0, entity_num, intel_pci_chipsets,
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
if (scrn == NULL)
|
|
return FALSE;
|
|
|
|
scrn->driverVersion = INTEL_VERSION;
|
|
scrn->driverName = INTEL_DRIVER_NAME;
|
|
scrn->name = INTEL_NAME;
|
|
scrn->Probe = NULL;
|
|
|
|
#if !KMS_ONLY
|
|
switch (DEVICE_ID(device)) {
|
|
case PCI_CHIP_I810:
|
|
case PCI_CHIP_I810_DC100:
|
|
case PCI_CHIP_I810_E:
|
|
case PCI_CHIP_I815:
|
|
return lg_i810_init(scrn);
|
|
}
|
|
#endif
|
|
|
|
switch (get_accel_method()) {
|
|
#if USE_SNA
|
|
case SNA: return sna_init_scrn(scrn, entity_num);
|
|
#endif
|
|
|
|
#if USE_UXA
|
|
case UXA: return intel_init_scrn(scrn);
|
|
#endif
|
|
|
|
default: return FALSE;
|
|
}
|
|
}
|
|
|
|
#ifdef XFree86LOADER
|
|
|
|
static MODULESETUPPROTO(intel_setup);
|
|
|
|
static XF86ModuleVersionInfo intel_version = {
|
|
"intel",
|
|
MODULEVENDORSTRING,
|
|
MODINFOSTRING1,
|
|
MODINFOSTRING2,
|
|
XORG_VERSION_CURRENT,
|
|
INTEL_VERSION_MAJOR, INTEL_VERSION_MINOR, INTEL_VERSION_PATCH,
|
|
ABI_CLASS_VIDEODRV,
|
|
ABI_VIDEODRV_VERSION,
|
|
MOD_CLASS_VIDEODRV,
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
static const OptionInfoRec *
|
|
intel_available_options(int chipid, int busid)
|
|
{
|
|
switch (chipid) {
|
|
#if !KMS_ONLY
|
|
case PCI_CHIP_I810:
|
|
case PCI_CHIP_I810_DC100:
|
|
case PCI_CHIP_I810_E:
|
|
case PCI_CHIP_I815:
|
|
return lg_i810_available_options(chipid, busid);
|
|
#endif
|
|
|
|
default:
|
|
return intel_options;
|
|
}
|
|
}
|
|
|
|
static DriverRec intel = {
|
|
INTEL_VERSION,
|
|
INTEL_DRIVER_NAME,
|
|
intel_identify,
|
|
NULL,
|
|
intel_available_options,
|
|
NULL,
|
|
0,
|
|
intel_driver_func,
|
|
intel_device_match,
|
|
intel_pci_probe
|
|
};
|
|
|
|
static pointer intel_setup(pointer module,
|
|
pointer opts,
|
|
int *errmaj,
|
|
int *errmin)
|
|
{
|
|
static Bool setupDone = 0;
|
|
|
|
/* This module should be loaded only once, but check to be sure.
|
|
*/
|
|
if (!setupDone) {
|
|
setupDone = 1;
|
|
xf86AddDriver(&intel, module, HaveDriverFuncs);
|
|
|
|
/*
|
|
* The return value must be non-NULL on success even though there
|
|
* is no TearDownProc.
|
|
*/
|
|
return (pointer) 1;
|
|
} else {
|
|
if (errmaj)
|
|
*errmaj = LDR_ONCEONLY;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
_X_EXPORT XF86ModuleData intelModuleData = { &intel_version, intel_setup, NULL };
|
|
#endif
|