提交 98b98d31 编写于 作者: L Linus Torvalds

Merge branch 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (169 commits)
  drivers/gpu/drm/radeon/atom.c: fix warning
  drm/radeon/kms: bump kms version number
  drm/radeon/kms: properly set num banks for fusion asics
  drm/radeon/kms/atom: move dig phy init out of modesetting
  drm/radeon/kms/cayman: fix typo in register mask
  drm/radeon/kms: fix typo in spread spectrum code
  drm/radeon/kms: fix tile_config value reported to userspace on cayman.
  drm/radeon/kms: fix incorrect comparison in cayman setup code.
  drm/radeon/kms: add wait idle ioctl for eg->cayman
  drm/radeon/cayman: setup hdp to invalidate and flush when asked
  drm/radeon/evergreen/btc/fusion: setup hdp to invalidate and flush when asked
  agp/uninorth: Fix lockups with radeon KMS and >1x.
  drm/radeon/kms: the SS_Id field in the LCD table if for LVDS only
  drm/radeon/kms: properly set the CLK_REF bit for DCE3 devices
  drm/radeon/kms: fixup eDP connector handling
  drm/radeon/kms: bail early for eDP in hotplug callback
  drm/radeon/kms: simplify hotplug handler logic
  drm/radeon/kms: rewrite DP handling
  drm/radeon/kms/atom: add support for setting DP panel mode
  drm/radeon/kms: atombios.h updates for DP panel mode
  ...
...@@ -2245,10 +2245,10 @@ F: drivers/gpu/drm/ ...@@ -2245,10 +2245,10 @@ F: drivers/gpu/drm/
F: include/drm/ F: include/drm/
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets) INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
M: Chris Wilson <chris@chris-wilson.co.uk> M: Keith Packard <keithp@keithp.com>
L: intel-gfx@lists.freedesktop.org (subscribers-only) L: intel-gfx@lists.freedesktop.org (subscribers-only)
L: dri-devel@lists.freedesktop.org L: dri-devel@lists.freedesktop.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux-2.6.git
S: Supported S: Supported
F: drivers/gpu/drm/i915 F: drivers/gpu/drm/i915
F: include/drm/i915* F: include/drm/i915*
......
...@@ -903,6 +903,9 @@ static struct pci_device_id agp_intel_pci_table[] = { ...@@ -903,6 +903,9 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB), ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB),
ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB), ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB),
ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB), ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB),
ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB),
ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB),
ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB),
{ } { }
}; };
......
...@@ -225,6 +225,14 @@ ...@@ -225,6 +225,14 @@
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG 0x0126 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG 0x0126
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB 0x0108 /* Server */ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB 0x0108 /* Server */
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG 0x010A #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG 0x010A
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB 0x0150 /* Desktop */
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG 0x0152
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG 0x0162
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB 0x0154 /* Mobile */
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG 0x0156
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG 0x0166
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB 0x0158 /* Server */
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG 0x015A
int intel_gmch_probe(struct pci_dev *pdev, int intel_gmch_probe(struct pci_dev *pdev,
struct agp_bridge_data *bridge); struct agp_bridge_data *bridge);
......
...@@ -1420,6 +1420,16 @@ static const struct intel_gtt_driver_description { ...@@ -1420,6 +1420,16 @@ static const struct intel_gtt_driver_description {
"Sandybridge", &sandybridge_gtt_driver }, "Sandybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
"Sandybridge", &sandybridge_gtt_driver }, "Sandybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG,
"Ivybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG,
"Ivybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG,
"Ivybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG,
"Ivybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG,
"Ivybridge", &sandybridge_gtt_driver },
{ 0, NULL, NULL } { 0, NULL, NULL }
}; };
......
...@@ -80,7 +80,7 @@ static void uninorth_tlbflush(struct agp_memory *mem) ...@@ -80,7 +80,7 @@ static void uninorth_tlbflush(struct agp_memory *mem)
ctrl | UNI_N_CFG_GART_INVAL); ctrl | UNI_N_CFG_GART_INVAL);
pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, ctrl); pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, ctrl);
if (uninorth_rev <= 0x30) { if (!mem && uninorth_rev <= 0x30) {
pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
ctrl | UNI_N_CFG_GART_2xRESET); ctrl | UNI_N_CFG_GART_2xRESET);
pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
......
...@@ -1412,6 +1412,64 @@ bool drm_detect_monitor_audio(struct edid *edid) ...@@ -1412,6 +1412,64 @@ bool drm_detect_monitor_audio(struct edid *edid)
} }
EXPORT_SYMBOL(drm_detect_monitor_audio); EXPORT_SYMBOL(drm_detect_monitor_audio);
/**
* drm_add_display_info - pull display info out if present
* @edid: EDID data
* @info: display info (attached to connector)
*
* Grab any available display info and stuff it into the drm_display_info
* structure that's part of the connector. Useful for tracking bpp and
* color spaces.
*/
static void drm_add_display_info(struct edid *edid,
struct drm_display_info *info)
{
info->width_mm = edid->width_cm * 10;
info->height_mm = edid->height_cm * 10;
/* driver figures it out in this case */
info->bpc = 0;
info->color_formats = 0;
/* Only defined for 1.4 with digital displays */
if (edid->revision < 4)
return;
if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
return;
switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
case DRM_EDID_DIGITAL_DEPTH_6:
info->bpc = 6;
break;
case DRM_EDID_DIGITAL_DEPTH_8:
info->bpc = 8;
break;
case DRM_EDID_DIGITAL_DEPTH_10:
info->bpc = 10;
break;
case DRM_EDID_DIGITAL_DEPTH_12:
info->bpc = 12;
break;
case DRM_EDID_DIGITAL_DEPTH_14:
info->bpc = 14;
break;
case DRM_EDID_DIGITAL_DEPTH_16:
info->bpc = 16;
break;
case DRM_EDID_DIGITAL_DEPTH_UNDEF:
default:
info->bpc = 0;
break;
}
info->color_formats = DRM_COLOR_FORMAT_RGB444;
if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444)
info->color_formats = DRM_COLOR_FORMAT_YCRCB444;
if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422)
info->color_formats = DRM_COLOR_FORMAT_YCRCB422;
}
/** /**
* drm_add_edid_modes - add modes from EDID data, if available * drm_add_edid_modes - add modes from EDID data, if available
* @connector: connector we're probing * @connector: connector we're probing
...@@ -1460,8 +1518,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) ...@@ -1460,8 +1518,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
edid_fixup_preferred(connector, quirks); edid_fixup_preferred(connector, quirks);
connector->display_info.width_mm = edid->width_cm * 10; drm_add_display_info(edid, &connector->display_info);
connector->display_info.height_mm = edid->height_cm * 10;
return num_modes; return num_modes;
} }
......
...@@ -70,174 +70,50 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) ...@@ -70,174 +70,50 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
} }
EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
/**
* drm_fb_helper_connector_parse_command_line - parse command line for connector
* @connector - connector to parse line for
* @mode_option - per connector mode option
*
* This parses the connector specific then generic command lines for
* modes and options to configure the connector.
*
* This uses the same parameters as the fb modedb.c, except for extra
* <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
*
* enable/enable Digital/disable bit at the end
*/
static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
const char *mode_option)
{
const char *name;
unsigned int namelen;
int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
int i;
enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
struct drm_fb_helper_cmdline_mode *cmdline_mode;
struct drm_connector *connector;
if (!fb_helper_conn)
return false;
connector = fb_helper_conn->connector;
cmdline_mode = &fb_helper_conn->cmdline_mode;
if (!mode_option)
mode_option = fb_mode_option;
if (!mode_option) {
cmdline_mode->specified = false;
return false;
}
name = mode_option;
namelen = strlen(name);
for (i = namelen-1; i >= 0; i--) {
switch (name[i]) {
case '@':
namelen = i;
if (!refresh_specified && !bpp_specified &&
!yres_specified) {
refresh = simple_strtol(&name[i+1], NULL, 10);
refresh_specified = 1;
if (cvt || rb)
cvt = 0;
} else
goto done;
break;
case '-':
namelen = i;
if (!bpp_specified && !yres_specified) {
bpp = simple_strtol(&name[i+1], NULL, 10);
bpp_specified = 1;
if (cvt || rb)
cvt = 0;
} else
goto done;
break;
case 'x':
if (!yres_specified) {
yres = simple_strtol(&name[i+1], NULL, 10);
yres_specified = 1;
} else
goto done;
case '0' ... '9':
break;
case 'M':
if (!yres_specified)
cvt = 1;
break;
case 'R':
if (cvt)
rb = 1;
break;
case 'm':
if (!cvt)
margins = 1;
break;
case 'i':
if (!cvt)
interlace = 1;
break;
case 'e':
force = DRM_FORCE_ON;
break;
case 'D':
if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
(connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
force = DRM_FORCE_ON;
else
force = DRM_FORCE_ON_DIGITAL;
break;
case 'd':
force = DRM_FORCE_OFF;
break;
default:
goto done;
}
}
if (i < 0 && yres_specified) {
xres = simple_strtol(name, NULL, 10);
res_specified = 1;
}
done:
DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
drm_get_connector_name(connector), xres, yres,
(refresh) ? refresh : 60, (rb) ? " reduced blanking" :
"", (margins) ? " with margins" : "", (interlace) ?
" interlaced" : "");
if (force) {
const char *s;
switch (force) {
case DRM_FORCE_OFF: s = "OFF"; break;
case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
default:
case DRM_FORCE_ON: s = "ON"; break;
}
DRM_INFO("forcing %s connector %s\n",
drm_get_connector_name(connector), s);
connector->force = force;
}
if (res_specified) {
cmdline_mode->specified = true;
cmdline_mode->xres = xres;
cmdline_mode->yres = yres;
}
if (refresh_specified) {
cmdline_mode->refresh_specified = true;
cmdline_mode->refresh = refresh;
}
if (bpp_specified) {
cmdline_mode->bpp_specified = true;
cmdline_mode->bpp = bpp;
}
cmdline_mode->rb = rb ? true : false;
cmdline_mode->cvt = cvt ? true : false;
cmdline_mode->interlace = interlace ? true : false;
return true;
}
static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
{ {
struct drm_fb_helper_connector *fb_helper_conn; struct drm_fb_helper_connector *fb_helper_conn;
int i; int i;
for (i = 0; i < fb_helper->connector_count; i++) { for (i = 0; i < fb_helper->connector_count; i++) {
struct drm_cmdline_mode *mode;
struct drm_connector *connector;
char *option = NULL; char *option = NULL;
fb_helper_conn = fb_helper->connector_info[i]; fb_helper_conn = fb_helper->connector_info[i];
connector = fb_helper_conn->connector;
mode = &fb_helper_conn->cmdline_mode;
/* do something on return - turn off connector maybe */ /* do something on return - turn off connector maybe */
if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option)) if (fb_get_options(drm_get_connector_name(connector), &option))
continue; continue;
drm_fb_helper_connector_parse_command_line(fb_helper_conn, option); if (drm_mode_parse_command_line_for_connector(option,
connector,
mode)) {
if (mode->force) {
const char *s;
switch (mode->force) {
case DRM_FORCE_OFF: s = "OFF"; break;
case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
default:
case DRM_FORCE_ON: s = "ON"; break;
}
DRM_INFO("forcing %s connector %s\n",
drm_get_connector_name(connector), s);
connector->force = mode->force;
}
DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
drm_get_connector_name(connector),
mode->xres, mode->yres,
mode->refresh_specified ? mode->refresh : 60,
mode->rb ? " reduced blanking" : "",
mode->margins ? " with margins" : "",
mode->interlace ? " interlaced" : "");
}
} }
return 0; return 0;
} }
...@@ -901,7 +777,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, ...@@ -901,7 +777,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
/* first up get a count of crtcs now in use and new min/maxes width/heights */ /* first up get a count of crtcs now in use and new min/maxes width/heights */
for (i = 0; i < fb_helper->connector_count; i++) { for (i = 0; i < fb_helper->connector_count; i++) {
struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
struct drm_fb_helper_cmdline_mode *cmdline_mode; struct drm_cmdline_mode *cmdline_mode;
cmdline_mode = &fb_helper_conn->cmdline_mode; cmdline_mode = &fb_helper_conn->cmdline_mode;
...@@ -1123,7 +999,7 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_conn ...@@ -1123,7 +999,7 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_conn
static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
{ {
struct drm_fb_helper_cmdline_mode *cmdline_mode; struct drm_cmdline_mode *cmdline_mode;
cmdline_mode = &fb_connector->cmdline_mode; cmdline_mode = &fb_connector->cmdline_mode;
return cmdline_mode->specified; return cmdline_mode->specified;
} }
...@@ -1131,7 +1007,7 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) ...@@ -1131,7 +1007,7 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
int width, int height) int width, int height)
{ {
struct drm_fb_helper_cmdline_mode *cmdline_mode; struct drm_cmdline_mode *cmdline_mode;
struct drm_display_mode *mode = NULL; struct drm_display_mode *mode = NULL;
cmdline_mode = &fb_helper_conn->cmdline_mode; cmdline_mode = &fb_helper_conn->cmdline_mode;
...@@ -1163,19 +1039,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne ...@@ -1163,19 +1039,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
} }
create_mode: create_mode:
if (cmdline_mode->cvt) mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
mode = drm_cvt_mode(fb_helper_conn->connector->dev, cmdline_mode);
cmdline_mode->xres, cmdline_mode->yres,
cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
cmdline_mode->rb, cmdline_mode->interlace,
cmdline_mode->margins);
else
mode = drm_gtf_mode(fb_helper_conn->connector->dev,
cmdline_mode->xres, cmdline_mode->yres,
cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
cmdline_mode->interlace,
cmdline_mode->margins);
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
list_add(&mode->head, &fb_helper_conn->connector->modes); list_add(&mode->head, &fb_helper_conn->connector->modes);
return mode; return mode;
} }
......
...@@ -684,10 +684,11 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, ...@@ -684,10 +684,11 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
*/ */
*vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns); *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns);
DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %d.%d -> %d.%d [e %d us, %d rep]\n", DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
crtc, (int) vbl_status, hpos, vpos, raw_time.tv_sec, crtc, (int)vbl_status, hpos, vpos,
raw_time.tv_usec, vblank_time->tv_sec, vblank_time->tv_usec, (long)raw_time.tv_sec, (long)raw_time.tv_usec,
(int) duration_ns/1000, i); (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
(int)duration_ns/1000, i);
vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
if (invbl) if (invbl)
......
...@@ -974,3 +974,159 @@ void drm_mode_connector_list_update(struct drm_connector *connector) ...@@ -974,3 +974,159 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
} }
} }
EXPORT_SYMBOL(drm_mode_connector_list_update); EXPORT_SYMBOL(drm_mode_connector_list_update);
/**
* drm_mode_parse_command_line_for_connector - parse command line for connector
* @mode_option - per connector mode option
* @connector - connector to parse line for
*
* This parses the connector specific then generic command lines for
* modes and options to configure the connector.
*
* This uses the same parameters as the fb modedb.c, except for extra
* <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
*
* enable/enable Digital/disable bit at the end
*/
bool drm_mode_parse_command_line_for_connector(const char *mode_option,
struct drm_connector *connector,
struct drm_cmdline_mode *mode)
{
const char *name;
unsigned int namelen;
int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
int i;
enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
#ifdef CONFIG_FB
if (!mode_option)
mode_option = fb_mode_option;
#endif
if (!mode_option) {
mode->specified = false;
return false;
}
name = mode_option;
namelen = strlen(name);
for (i = namelen-1; i >= 0; i--) {
switch (name[i]) {
case '@':
namelen = i;
if (!refresh_specified && !bpp_specified &&
!yres_specified) {
refresh = simple_strtol(&name[i+1], NULL, 10);
refresh_specified = 1;
if (cvt || rb)
cvt = 0;
} else
goto done;
break;
case '-':
namelen = i;
if (!bpp_specified && !yres_specified) {
bpp = simple_strtol(&name[i+1], NULL, 10);
bpp_specified = 1;
if (cvt || rb)
cvt = 0;
} else
goto done;
break;
case 'x':
if (!yres_specified) {
yres = simple_strtol(&name[i+1], NULL, 10);
yres_specified = 1;
} else
goto done;
case '0' ... '9':
break;
case 'M':
if (!yres_specified)
cvt = 1;
break;
case 'R':
if (cvt)
rb = 1;
break;
case 'm':
if (!cvt)
margins = 1;
break;
case 'i':
if (!cvt)
interlace = 1;
break;
case 'e':
force = DRM_FORCE_ON;
break;
case 'D':
if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
(connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
force = DRM_FORCE_ON;
else
force = DRM_FORCE_ON_DIGITAL;
break;
case 'd':
force = DRM_FORCE_OFF;
break;
default:
goto done;
}
}
if (i < 0 && yres_specified) {
xres = simple_strtol(name, NULL, 10);
res_specified = 1;
}
done:
if (res_specified) {
mode->specified = true;
mode->xres = xres;
mode->yres = yres;
}
if (refresh_specified) {
mode->refresh_specified = true;
mode->refresh = refresh;
}
if (bpp_specified) {
mode->bpp_specified = true;
mode->bpp = bpp;
}
mode->rb = rb ? true : false;
mode->cvt = cvt ? true : false;
mode->interlace = interlace ? true : false;
mode->force = force;
return true;
}
EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
struct drm_display_mode *
drm_mode_create_from_cmdline_mode(struct drm_device *dev,
struct drm_cmdline_mode *cmd)
{
struct drm_display_mode *mode;
if (cmd->cvt)
mode = drm_cvt_mode(dev,
cmd->xres, cmd->yres,
cmd->refresh_specified ? cmd->refresh : 60,
cmd->rb, cmd->interlace,
cmd->margins);
else
mode = drm_gtf_mode(dev,
cmd->xres, cmd->yres,
cmd->refresh_specified ? cmd->refresh : 60,
cmd->interlace,
cmd->margins);
if (!mode)
return NULL;
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
return mode;
}
EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
...@@ -62,6 +62,26 @@ struct idr drm_minors_idr; ...@@ -62,6 +62,26 @@ struct idr drm_minors_idr;
struct class *drm_class; struct class *drm_class;
struct proc_dir_entry *drm_proc_root; struct proc_dir_entry *drm_proc_root;
struct dentry *drm_debugfs_root; struct dentry *drm_debugfs_root;
int drm_err(const char *func, const char *format, ...)
{
struct va_format vaf;
va_list args;
int r;
va_start(args, format);
vaf.fmt = format;
vaf.va = &args;
r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
va_end(args);
return r;
}
EXPORT_SYMBOL(drm_err);
void drm_ut_debug_printk(unsigned int request_level, void drm_ut_debug_printk(unsigned int request_level,
const char *prefix, const char *prefix,
const char *function_name, const char *function_name,
...@@ -78,6 +98,7 @@ void drm_ut_debug_printk(unsigned int request_level, ...@@ -78,6 +98,7 @@ void drm_ut_debug_printk(unsigned int request_level,
} }
} }
EXPORT_SYMBOL(drm_ut_debug_printk); EXPORT_SYMBOL(drm_ut_debug_printk);
static int drm_minor_get_id(struct drm_device *dev, int type) static int drm_minor_get_id(struct drm_device *dev, int type)
{ {
int new_id; int new_id;
......
...@@ -106,11 +106,12 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj) ...@@ -106,11 +106,12 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj)
} }
} }
static const char *agp_type_str(int type) static const char *cache_level_str(int type)
{ {
switch (type) { switch (type) {
case 0: return " uncached"; case I915_CACHE_NONE: return " uncached";
case 1: return " snooped"; case I915_CACHE_LLC: return " snooped (LLC)";
case I915_CACHE_LLC_MLC: return " snooped (LLC+MLC)";
default: return ""; default: return "";
} }
} }
...@@ -127,7 +128,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) ...@@ -127,7 +128,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
obj->base.write_domain, obj->base.write_domain,
obj->last_rendering_seqno, obj->last_rendering_seqno,
obj->last_fenced_seqno, obj->last_fenced_seqno,
agp_type_str(obj->agp_type == AGP_USER_CACHED_MEMORY), cache_level_str(obj->cache_level),
obj->dirty ? " dirty" : "", obj->dirty ? " dirty" : "",
obj->madv == I915_MADV_DONTNEED ? " purgeable" : ""); obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
if (obj->base.name) if (obj->base.name)
...@@ -714,7 +715,7 @@ static void print_error_buffers(struct seq_file *m, ...@@ -714,7 +715,7 @@ static void print_error_buffers(struct seq_file *m,
dirty_flag(err->dirty), dirty_flag(err->dirty),
purgeable_flag(err->purgeable), purgeable_flag(err->purgeable),
ring_str(err->ring), ring_str(err->ring),
agp_type_str(err->agp_type)); cache_level_str(err->cache_level));
if (err->name) if (err->name)
seq_printf(m, " (name: %d)", err->name); seq_printf(m, " (name: %d)", err->name);
...@@ -852,6 +853,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) ...@@ -852,6 +853,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
if (IS_GEN5(dev)) { if (IS_GEN5(dev)) {
u16 rgvswctl = I915_READ16(MEMSWCTL); u16 rgvswctl = I915_READ16(MEMSWCTL);
...@@ -873,7 +875,11 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) ...@@ -873,7 +875,11 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
int max_freq; int max_freq;
/* RPSTAT1 is in the GT power well */ /* RPSTAT1 is in the GT power well */
__gen6_gt_force_wake_get(dev_priv); ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
gen6_gt_force_wake_get(dev_priv);
rpstat = I915_READ(GEN6_RPSTAT1); rpstat = I915_READ(GEN6_RPSTAT1);
rpupei = I915_READ(GEN6_RP_CUR_UP_EI); rpupei = I915_READ(GEN6_RP_CUR_UP_EI);
...@@ -883,6 +889,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) ...@@ -883,6 +889,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
rpcurdown = I915_READ(GEN6_RP_CUR_DOWN); rpcurdown = I915_READ(GEN6_RP_CUR_DOWN);
rpprevdown = I915_READ(GEN6_RP_PREV_DOWN); rpprevdown = I915_READ(GEN6_RP_PREV_DOWN);
gen6_gt_force_wake_put(dev_priv);
mutex_unlock(&dev->struct_mutex);
seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat); seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat);
seq_printf(m, "Render p-state ratio: %d\n", seq_printf(m, "Render p-state ratio: %d\n",
...@@ -917,8 +926,6 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) ...@@ -917,8 +926,6 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
max_freq = rp_state_cap & 0xff; max_freq = rp_state_cap & 0xff;
seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
max_freq * 50); max_freq * 50);
__gen6_gt_force_wake_put(dev_priv);
} else { } else {
seq_printf(m, "no P-state info available\n"); seq_printf(m, "no P-state info available\n");
} }
...@@ -1058,6 +1065,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused) ...@@ -1058,6 +1065,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
case FBC_MULTIPLE_PIPES: case FBC_MULTIPLE_PIPES:
seq_printf(m, "multiple pipes are enabled"); seq_printf(m, "multiple pipes are enabled");
break; break;
case FBC_MODULE_PARAM:
seq_printf(m, "disabled per module param (default off)");
break;
default: default:
seq_printf(m, "unknown reason"); seq_printf(m, "unknown reason");
} }
...@@ -1186,6 +1196,42 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) ...@@ -1186,6 +1196,42 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
return 0; return 0;
} }
static int i915_context_status(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
ret = mutex_lock_interruptible(&dev->mode_config.mutex);
if (ret)
return ret;
seq_printf(m, "power context ");
describe_obj(m, dev_priv->pwrctx);
seq_printf(m, "\n");
seq_printf(m, "render context ");
describe_obj(m, dev_priv->renderctx);
seq_printf(m, "\n");
mutex_unlock(&dev->mode_config.mutex);
return 0;
}
static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
seq_printf(m, "forcewake count = %d\n",
atomic_read(&dev_priv->forcewake_count));
return 0;
}
static int static int
i915_wedged_open(struct inode *inode, i915_wedged_open(struct inode *inode,
struct file *filp) struct file *filp)
...@@ -1288,6 +1334,67 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) ...@@ -1288,6 +1334,67 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
return drm_add_fake_info_node(minor, ent, &i915_wedged_fops); return drm_add_fake_info_node(minor, ent, &i915_wedged_fops);
} }
static int i915_forcewake_open(struct inode *inode, struct file *file)
{
struct drm_device *dev = inode->i_private;
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
if (!IS_GEN6(dev))
return 0;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
gen6_gt_force_wake_get(dev_priv);
mutex_unlock(&dev->struct_mutex);
return 0;
}
int i915_forcewake_release(struct inode *inode, struct file *file)
{
struct drm_device *dev = inode->i_private;
struct drm_i915_private *dev_priv = dev->dev_private;
if (!IS_GEN6(dev))
return 0;
/*
* It's bad that we can potentially hang userspace if struct_mutex gets
* forever stuck. However, if we cannot acquire this lock it means that
* almost certainly the driver has hung, is not unload-able. Therefore
* hanging here is probably a minor inconvenience not to be seen my
* almost every user.
*/
mutex_lock(&dev->struct_mutex);
gen6_gt_force_wake_put(dev_priv);
mutex_unlock(&dev->struct_mutex);
return 0;
}
static const struct file_operations i915_forcewake_fops = {
.owner = THIS_MODULE,
.open = i915_forcewake_open,
.release = i915_forcewake_release,
};
static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
struct dentry *ent;
ent = debugfs_create_file("i915_forcewake_user",
S_IRUSR,
root, dev,
&i915_forcewake_fops);
if (IS_ERR(ent))
return PTR_ERR(ent);
return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops);
}
static struct drm_info_list i915_debugfs_list[] = { static struct drm_info_list i915_debugfs_list[] = {
{"i915_capabilities", i915_capabilities, 0}, {"i915_capabilities", i915_capabilities, 0},
{"i915_gem_objects", i915_gem_object_info, 0}, {"i915_gem_objects", i915_gem_object_info, 0},
...@@ -1324,6 +1431,8 @@ static struct drm_info_list i915_debugfs_list[] = { ...@@ -1324,6 +1431,8 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_sr_status", i915_sr_status, 0}, {"i915_sr_status", i915_sr_status, 0},
{"i915_opregion", i915_opregion, 0}, {"i915_opregion", i915_opregion, 0},
{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
{"i915_context_status", i915_context_status, 0},
{"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
}; };
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
...@@ -1335,6 +1444,10 @@ int i915_debugfs_init(struct drm_minor *minor) ...@@ -1335,6 +1444,10 @@ int i915_debugfs_init(struct drm_minor *minor)
if (ret) if (ret)
return ret; return ret;
ret = i915_forcewake_create(minor->debugfs_root, minor);
if (ret)
return ret;
return drm_debugfs_create_files(i915_debugfs_list, return drm_debugfs_create_files(i915_debugfs_list,
I915_DEBUGFS_ENTRIES, I915_DEBUGFS_ENTRIES,
minor->debugfs_root, minor); minor->debugfs_root, minor);
...@@ -1344,6 +1457,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor) ...@@ -1344,6 +1457,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
{ {
drm_debugfs_remove_files(i915_debugfs_list, drm_debugfs_remove_files(i915_debugfs_list,
I915_DEBUGFS_ENTRIES, minor); I915_DEBUGFS_ENTRIES, minor);
drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops,
1, minor);
drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops, drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops,
1, minor); 1, minor);
} }
......
...@@ -571,7 +571,7 @@ static int i915_quiescent(struct drm_device *dev) ...@@ -571,7 +571,7 @@ static int i915_quiescent(struct drm_device *dev)
struct intel_ring_buffer *ring = LP_RING(dev->dev_private); struct intel_ring_buffer *ring = LP_RING(dev->dev_private);
i915_kernel_lost_context(dev); i915_kernel_lost_context(dev);
return intel_wait_ring_buffer(ring, ring->size - 8); return intel_wait_ring_idle(ring);
} }
static int i915_flush_ioctl(struct drm_device *dev, void *data, static int i915_flush_ioctl(struct drm_device *dev, void *data,
...@@ -1176,11 +1176,11 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev) ...@@ -1176,11 +1176,11 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
return can_switch; return can_switch;
} }
static int i915_load_modeset_init(struct drm_device *dev) static int i915_load_gem_init(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long prealloc_size, gtt_size, mappable_size; unsigned long prealloc_size, gtt_size, mappable_size;
int ret = 0; int ret;
prealloc_size = dev_priv->mm.gtt->stolen_size; prealloc_size = dev_priv->mm.gtt->stolen_size;
gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
...@@ -1204,7 +1204,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -1204,7 +1204,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
ret = i915_gem_init_ringbuffer(dev); ret = i915_gem_init_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
if (ret) if (ret)
goto out; return ret;
/* Try to set up FBC with a reasonable compressed buffer size */ /* Try to set up FBC with a reasonable compressed buffer size */
if (I915_HAS_FBC(dev) && i915_powersave) { if (I915_HAS_FBC(dev) && i915_powersave) {
...@@ -1222,6 +1222,13 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -1222,6 +1222,13 @@ static int i915_load_modeset_init(struct drm_device *dev)
/* Allow hardware batchbuffers unless told otherwise. */ /* Allow hardware batchbuffers unless told otherwise. */
dev_priv->allow_batchbuffer = 1; dev_priv->allow_batchbuffer = 1;
return 0;
}
static int i915_load_modeset_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
ret = intel_parse_bios(dev); ret = intel_parse_bios(dev);
if (ret) if (ret)
...@@ -1236,7 +1243,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -1236,7 +1243,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
*/ */
ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode); ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
if (ret && ret != -ENODEV) if (ret && ret != -ENODEV)
goto cleanup_ringbuffer; goto out;
intel_register_dsm_handler(); intel_register_dsm_handler();
...@@ -1253,10 +1260,40 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -1253,10 +1260,40 @@ static int i915_load_modeset_init(struct drm_device *dev)
intel_modeset_init(dev); intel_modeset_init(dev);
ret = drm_irq_install(dev); ret = i915_load_gem_init(dev);
if (ret) if (ret)
goto cleanup_vga_switcheroo; goto cleanup_vga_switcheroo;
intel_modeset_gem_init(dev);
if (IS_IVYBRIDGE(dev)) {
/* Share pre & uninstall handlers with ILK/SNB */
dev->driver->irq_handler = ivybridge_irq_handler;
dev->driver->irq_preinstall = ironlake_irq_preinstall;
dev->driver->irq_postinstall = ivybridge_irq_postinstall;
dev->driver->irq_uninstall = ironlake_irq_uninstall;
dev->driver->enable_vblank = ivybridge_enable_vblank;
dev->driver->disable_vblank = ivybridge_disable_vblank;
} else if (HAS_PCH_SPLIT(dev)) {
dev->driver->irq_handler = ironlake_irq_handler;
dev->driver->irq_preinstall = ironlake_irq_preinstall;
dev->driver->irq_postinstall = ironlake_irq_postinstall;
dev->driver->irq_uninstall = ironlake_irq_uninstall;
dev->driver->enable_vblank = ironlake_enable_vblank;
dev->driver->disable_vblank = ironlake_disable_vblank;
} else {
dev->driver->irq_preinstall = i915_driver_irq_preinstall;
dev->driver->irq_postinstall = i915_driver_irq_postinstall;
dev->driver->irq_uninstall = i915_driver_irq_uninstall;
dev->driver->irq_handler = i915_driver_irq_handler;
dev->driver->enable_vblank = i915_enable_vblank;
dev->driver->disable_vblank = i915_disable_vblank;
}
ret = drm_irq_install(dev);
if (ret)
goto cleanup_gem;
/* Always safe in the mode setting case. */ /* Always safe in the mode setting case. */
/* FIXME: do pre/post-mode set stuff in core KMS code */ /* FIXME: do pre/post-mode set stuff in core KMS code */
dev->vblank_disable_allowed = 1; dev->vblank_disable_allowed = 1;
...@@ -1274,14 +1311,14 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -1274,14 +1311,14 @@ static int i915_load_modeset_init(struct drm_device *dev)
cleanup_irq: cleanup_irq:
drm_irq_uninstall(dev); drm_irq_uninstall(dev);
cleanup_gem:
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
cleanup_vga_switcheroo: cleanup_vga_switcheroo:
vga_switcheroo_unregister_client(dev->pdev); vga_switcheroo_unregister_client(dev->pdev);
cleanup_vga_client: cleanup_vga_client:
vga_client_register(dev->pdev, NULL, NULL, NULL); vga_client_register(dev->pdev, NULL, NULL, NULL);
cleanup_ringbuffer:
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
out: out:
return ret; return ret;
} }
...@@ -1982,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -1982,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) { if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) {
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
dev->driver->get_vblank_counter = gm45_get_vblank_counter; dev->driver->get_vblank_counter = gm45_get_vblank_counter;
} }
...@@ -2025,6 +2062,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -2025,6 +2062,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->irq_lock);
spin_lock_init(&dev_priv->error_lock); spin_lock_init(&dev_priv->error_lock);
spin_lock_init(&dev_priv->rps_lock);
if (IS_MOBILE(dev) || !IS_GEN2(dev)) if (IS_MOBILE(dev) || !IS_GEN2(dev))
dev_priv->num_pipe = 2; dev_priv->num_pipe = 2;
......
...@@ -52,9 +52,12 @@ module_param_named(powersave, i915_powersave, int, 0600); ...@@ -52,9 +52,12 @@ module_param_named(powersave, i915_powersave, int, 0600);
unsigned int i915_semaphores = 0; unsigned int i915_semaphores = 0;
module_param_named(semaphores, i915_semaphores, int, 0600); module_param_named(semaphores, i915_semaphores, int, 0600);
unsigned int i915_enable_rc6 = 0; unsigned int i915_enable_rc6 = 1;
module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
unsigned int i915_enable_fbc = 0;
module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
unsigned int i915_lvds_downclock = 0; unsigned int i915_lvds_downclock = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
...@@ -169,7 +172,7 @@ static const struct intel_device_info intel_ironlake_d_info = { ...@@ -169,7 +172,7 @@ static const struct intel_device_info intel_ironlake_d_info = {
static const struct intel_device_info intel_ironlake_m_info = { static const struct intel_device_info intel_ironlake_m_info = {
.gen = 5, .is_mobile = 1, .gen = 5, .is_mobile = 1,
.need_gfx_hws = 1, .has_hotplug = 1, .need_gfx_hws = 1, .has_hotplug = 1,
.has_fbc = 0, /* disabled due to buggy hardware */ .has_fbc = 1,
.has_bsd_ring = 1, .has_bsd_ring = 1,
}; };
...@@ -188,6 +191,21 @@ static const struct intel_device_info intel_sandybridge_m_info = { ...@@ -188,6 +191,21 @@ static const struct intel_device_info intel_sandybridge_m_info = {
.has_blt_ring = 1, .has_blt_ring = 1,
}; };
static const struct intel_device_info intel_ivybridge_d_info = {
.is_ivybridge = 1, .gen = 7,
.need_gfx_hws = 1, .has_hotplug = 1,
.has_bsd_ring = 1,
.has_blt_ring = 1,
};
static const struct intel_device_info intel_ivybridge_m_info = {
.is_ivybridge = 1, .gen = 7, .is_mobile = 1,
.need_gfx_hws = 1, .has_hotplug = 1,
.has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */
.has_bsd_ring = 1,
.has_blt_ring = 1,
};
static const struct pci_device_id pciidlist[] = { /* aka */ static const struct pci_device_id pciidlist[] = { /* aka */
INTEL_VGA_DEVICE(0x3577, &intel_i830_info), /* I830_M */ INTEL_VGA_DEVICE(0x3577, &intel_i830_info), /* I830_M */
INTEL_VGA_DEVICE(0x2562, &intel_845g_info), /* 845_G */ INTEL_VGA_DEVICE(0x2562, &intel_845g_info), /* 845_G */
...@@ -227,6 +245,11 @@ static const struct pci_device_id pciidlist[] = { /* aka */ ...@@ -227,6 +245,11 @@ static const struct pci_device_id pciidlist[] = { /* aka */
INTEL_VGA_DEVICE(0x0116, &intel_sandybridge_m_info), INTEL_VGA_DEVICE(0x0116, &intel_sandybridge_m_info),
INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info), INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info),
INTEL_VGA_DEVICE(0x010A, &intel_sandybridge_d_info), INTEL_VGA_DEVICE(0x010A, &intel_sandybridge_d_info),
INTEL_VGA_DEVICE(0x0156, &intel_ivybridge_m_info), /* GT1 mobile */
INTEL_VGA_DEVICE(0x0166, &intel_ivybridge_m_info), /* GT2 mobile */
INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */
INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
{0, 0, 0} {0, 0, 0}
}; };
...@@ -235,7 +258,9 @@ MODULE_DEVICE_TABLE(pci, pciidlist); ...@@ -235,7 +258,9 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
#endif #endif
#define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_DEVICE_ID_MASK 0xff00
#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00
#define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00
#define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00
void intel_detect_pch (struct drm_device *dev) void intel_detect_pch (struct drm_device *dev)
{ {
...@@ -254,16 +279,23 @@ void intel_detect_pch (struct drm_device *dev) ...@@ -254,16 +279,23 @@ void intel_detect_pch (struct drm_device *dev)
int id; int id;
id = pch->device & INTEL_PCH_DEVICE_ID_MASK; id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_IBX;
DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
} else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_CPT; dev_priv->pch_type = PCH_CPT;
DRM_DEBUG_KMS("Found CougarPoint PCH\n"); DRM_DEBUG_KMS("Found CougarPoint PCH\n");
} else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
/* PantherPoint is CPT compatible */
dev_priv->pch_type = PCH_CPT;
DRM_DEBUG_KMS("Found PatherPoint PCH\n");
} }
} }
pci_dev_put(pch); pci_dev_put(pch);
} }
} }
void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
{ {
int count; int count;
...@@ -279,12 +311,38 @@ void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) ...@@ -279,12 +311,38 @@ void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
udelay(10); udelay(10);
} }
void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) /*
* Generally this is called implicitly by the register read function. However,
* if some sequence requires the GT to not power down then this function should
* be called at the beginning of the sequence followed by a call to
* gen6_gt_force_wake_put() at the end of the sequence.
*/
void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
{
WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
/* Forcewake is atomic in case we get in here without the lock */
if (atomic_add_return(1, &dev_priv->forcewake_count) == 1)
__gen6_gt_force_wake_get(dev_priv);
}
static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
{ {
I915_WRITE_NOTRACE(FORCEWAKE, 0); I915_WRITE_NOTRACE(FORCEWAKE, 0);
POSTING_READ(FORCEWAKE); POSTING_READ(FORCEWAKE);
} }
/*
* see gen6_gt_force_wake_get()
*/
void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
{
WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
if (atomic_dec_and_test(&dev_priv->forcewake_count))
__gen6_gt_force_wake_put(dev_priv);
}
void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
{ {
int loop = 500; int loop = 500;
......
...@@ -188,7 +188,7 @@ struct drm_i915_error_state { ...@@ -188,7 +188,7 @@ struct drm_i915_error_state {
u32 dirty:1; u32 dirty:1;
u32 purgeable:1; u32 purgeable:1;
u32 ring:4; u32 ring:4;
u32 agp_type:1; u32 cache_level:2;
} *active_bo, *pinned_bo; } *active_bo, *pinned_bo;
u32 active_bo_count, pinned_bo_count; u32 active_bo_count, pinned_bo_count;
struct intel_overlay_error_state *overlay; struct intel_overlay_error_state *overlay;
...@@ -203,12 +203,19 @@ struct drm_i915_display_funcs { ...@@ -203,12 +203,19 @@ struct drm_i915_display_funcs {
int (*get_display_clock_speed)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev);
int (*get_fifo_size)(struct drm_device *dev, int plane); int (*get_fifo_size)(struct drm_device *dev, int plane);
void (*update_wm)(struct drm_device *dev); void (*update_wm)(struct drm_device *dev);
int (*crtc_mode_set)(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
int x, int y,
struct drm_framebuffer *old_fb);
void (*fdi_link_train)(struct drm_crtc *crtc);
void (*init_clock_gating)(struct drm_device *dev);
void (*init_pch_clock_gating)(struct drm_device *dev);
/* clock updates for mode set */ /* clock updates for mode set */
/* cursor updates */ /* cursor updates */
/* render clock increase/decrease */ /* render clock increase/decrease */
/* display clock increase/decrease */ /* display clock increase/decrease */
/* pll clock increase/decrease */ /* pll clock increase/decrease */
/* clock gating init */
}; };
struct intel_device_info { struct intel_device_info {
...@@ -223,6 +230,7 @@ struct intel_device_info { ...@@ -223,6 +230,7 @@ struct intel_device_info {
u8 is_pineview : 1; u8 is_pineview : 1;
u8 is_broadwater : 1; u8 is_broadwater : 1;
u8 is_crestline : 1; u8 is_crestline : 1;
u8 is_ivybridge : 1;
u8 has_fbc : 1; u8 has_fbc : 1;
u8 has_pipe_cxsr : 1; u8 has_pipe_cxsr : 1;
u8 has_hotplug : 1; u8 has_hotplug : 1;
...@@ -242,6 +250,7 @@ enum no_fbc_reason { ...@@ -242,6 +250,7 @@ enum no_fbc_reason {
FBC_BAD_PLANE, /* fbc not supported on plane */ FBC_BAD_PLANE, /* fbc not supported on plane */
FBC_NOT_TILED, /* buffer not tiled */ FBC_NOT_TILED, /* buffer not tiled */
FBC_MULTIPLE_PIPES, /* more than one pipe active */ FBC_MULTIPLE_PIPES, /* more than one pipe active */
FBC_MODULE_PARAM,
}; };
enum intel_pch { enum intel_pch {
...@@ -676,6 +685,10 @@ typedef struct drm_i915_private { ...@@ -676,6 +685,10 @@ typedef struct drm_i915_private {
bool mchbar_need_disable; bool mchbar_need_disable;
struct work_struct rps_work;
spinlock_t rps_lock;
u32 pm_iir;
u8 cur_delay; u8 cur_delay;
u8 min_delay; u8 min_delay;
u8 max_delay; u8 max_delay;
...@@ -703,8 +716,16 @@ typedef struct drm_i915_private { ...@@ -703,8 +716,16 @@ typedef struct drm_i915_private {
struct intel_fbdev *fbdev; struct intel_fbdev *fbdev;
struct drm_property *broadcast_rgb_property; struct drm_property *broadcast_rgb_property;
atomic_t forcewake_count;
} drm_i915_private_t; } drm_i915_private_t;
enum i915_cache_level {
I915_CACHE_NONE,
I915_CACHE_LLC,
I915_CACHE_LLC_MLC, /* gen6+ */
};
struct drm_i915_gem_object { struct drm_i915_gem_object {
struct drm_gem_object base; struct drm_gem_object base;
...@@ -791,6 +812,8 @@ struct drm_i915_gem_object { ...@@ -791,6 +812,8 @@ struct drm_i915_gem_object {
unsigned int pending_fenced_gpu_access:1; unsigned int pending_fenced_gpu_access:1;
unsigned int fenced_gpu_access:1; unsigned int fenced_gpu_access:1;
unsigned int cache_level:2;
struct page **pages; struct page **pages;
/** /**
...@@ -827,8 +850,6 @@ struct drm_i915_gem_object { ...@@ -827,8 +850,6 @@ struct drm_i915_gem_object {
/** Record of address bit 17 of each page at last unbind. */ /** Record of address bit 17 of each page at last unbind. */
unsigned long *bit_17; unsigned long *bit_17;
/** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */
uint32_t agp_type;
/** /**
* If present, while GEM_DOMAIN_CPU is in the read domain this array * If present, while GEM_DOMAIN_CPU is in the read domain this array
...@@ -915,13 +936,21 @@ enum intel_chip_family { ...@@ -915,13 +936,21 @@ enum intel_chip_family {
#define IS_G33(dev) (INTEL_INFO(dev)->is_g33) #define IS_G33(dev) (INTEL_INFO(dev)->is_g33)
#define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042) #define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042)
#define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046) #define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046)
#define IS_IVYBRIDGE(dev) (INTEL_INFO(dev)->is_ivybridge)
#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile)
/*
* The genX designation typically refers to the render engine, so render
* capability related checks should use IS_GEN, while display and other checks
* have their own (e.g. HAS_PCH_SPLIT for ILK+ display, IS_foo for particular
* chips, etc.).
*/
#define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2) #define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2)
#define IS_GEN3(dev) (INTEL_INFO(dev)->gen == 3) #define IS_GEN3(dev) (INTEL_INFO(dev)->gen == 3)
#define IS_GEN4(dev) (INTEL_INFO(dev)->gen == 4) #define IS_GEN4(dev) (INTEL_INFO(dev)->gen == 4)
#define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5) #define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5)
#define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6) #define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6)
#define IS_GEN7(dev) (INTEL_INFO(dev)->gen == 7)
#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring) #define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring)
#define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring) #define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring)
...@@ -948,8 +977,8 @@ enum intel_chip_family { ...@@ -948,8 +977,8 @@ enum intel_chip_family {
#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev)) #define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev))
#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev)) #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type) #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
...@@ -967,6 +996,7 @@ extern unsigned int i915_lvds_downclock; ...@@ -967,6 +996,7 @@ extern unsigned int i915_lvds_downclock;
extern unsigned int i915_panel_use_ssc; extern unsigned int i915_panel_use_ssc;
extern int i915_vbt_sdvo_panel_type; extern int i915_vbt_sdvo_panel_type;
extern unsigned int i915_enable_rc6; extern unsigned int i915_enable_rc6;
extern unsigned int i915_enable_fbc;
extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev); extern int i915_resume(struct drm_device *dev);
...@@ -1010,12 +1040,27 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); ...@@ -1010,12 +1040,27 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(struct drm_device * dev); extern void i915_driver_irq_preinstall(struct drm_device * dev);
extern int i915_driver_irq_postinstall(struct drm_device *dev); extern int i915_driver_irq_postinstall(struct drm_device *dev);
extern void i915_driver_irq_uninstall(struct drm_device * dev); extern void i915_driver_irq_uninstall(struct drm_device * dev);
extern irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS);
extern void ironlake_irq_preinstall(struct drm_device *dev);
extern int ironlake_irq_postinstall(struct drm_device *dev);
extern void ironlake_irq_uninstall(struct drm_device *dev);
extern irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS);
extern void ivybridge_irq_preinstall(struct drm_device *dev);
extern int ivybridge_irq_postinstall(struct drm_device *dev);
extern void ivybridge_irq_uninstall(struct drm_device *dev);
extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int i915_enable_vblank(struct drm_device *dev, int crtc); extern int i915_enable_vblank(struct drm_device *dev, int crtc);
extern void i915_disable_vblank(struct drm_device *dev, int crtc); extern void i915_disable_vblank(struct drm_device *dev, int crtc);
extern int ironlake_enable_vblank(struct drm_device *dev, int crtc);
extern void ironlake_disable_vblank(struct drm_device *dev, int crtc);
extern int ivybridge_enable_vblank(struct drm_device *dev, int crtc);
extern void ivybridge_disable_vblank(struct drm_device *dev, int crtc);
extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc); extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc);
extern int i915_vblank_swap(struct drm_device *dev, void *data, extern int i915_vblank_swap(struct drm_device *dev, void *data,
...@@ -1265,6 +1310,7 @@ static inline void intel_unregister_dsm_handler(void) { return; } ...@@ -1265,6 +1310,7 @@ static inline void intel_unregister_dsm_handler(void) { return; }
/* modesetting */ /* modesetting */
extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_gem_init(struct drm_device *dev);
extern void intel_modeset_cleanup(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev);
extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
extern void i8xx_disable_fbc(struct drm_device *dev); extern void i8xx_disable_fbc(struct drm_device *dev);
...@@ -1312,13 +1358,34 @@ extern void intel_display_print_error_state(struct seq_file *m, ...@@ -1312,13 +1358,34 @@ extern void intel_display_print_error_state(struct seq_file *m,
LOCK_TEST_WITH_RETURN(dev, file); \ LOCK_TEST_WITH_RETURN(dev, file); \
} while (0) } while (0)
/* On SNB platform, before reading ring registers forcewake bit
* must be set to prevent GT core from power down and stale values being
* returned.
*/
void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
/* We give fast paths for the really cool registers */
#define NEEDS_FORCE_WAKE(dev_priv, reg) \
(((dev_priv)->info->gen >= 6) && \
((reg) < 0x40000) && \
((reg) != FORCEWAKE))
#define __i915_read(x, y) \ #define __i915_read(x, y) \
static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
u##x val = read##y(dev_priv->regs + reg); \ u##x val = 0; \
if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
gen6_gt_force_wake_get(dev_priv); \
val = read##y(dev_priv->regs + reg); \
gen6_gt_force_wake_put(dev_priv); \
} else { \
val = read##y(dev_priv->regs + reg); \
} \
trace_i915_reg_rw(false, reg, val, sizeof(val)); \ trace_i915_reg_rw(false, reg, val, sizeof(val)); \
return val; \ return val; \
} }
__i915_read(8, b) __i915_read(8, b)
__i915_read(16, w) __i915_read(16, w)
__i915_read(32, l) __i915_read(32, l)
...@@ -1328,6 +1395,9 @@ __i915_read(64, q) ...@@ -1328,6 +1395,9 @@ __i915_read(64, q)
#define __i915_write(x, y) \ #define __i915_write(x, y) \
static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
trace_i915_reg_rw(true, reg, val, sizeof(val)); \ trace_i915_reg_rw(true, reg, val, sizeof(val)); \
if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
__gen6_gt_wait_for_fifo(dev_priv); \
} \
write##y(val, dev_priv->regs + reg); \ write##y(val, dev_priv->regs + reg); \
} }
__i915_write(8, b) __i915_write(8, b)
...@@ -1356,33 +1426,4 @@ __i915_write(64, q) ...@@ -1356,33 +1426,4 @@ __i915_write(64, q)
#define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) #define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg)
/* On SNB platform, before reading ring registers forcewake bit
* must be set to prevent GT core from power down and stale values being
* returned.
*/
void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
static inline u32 i915_gt_read(struct drm_i915_private *dev_priv, u32 reg)
{
u32 val;
if (dev_priv->info->gen >= 6) {
__gen6_gt_force_wake_get(dev_priv);
val = I915_READ(reg);
__gen6_gt_force_wake_put(dev_priv);
} else
val = I915_READ(reg);
return val;
}
static inline void i915_gt_write(struct drm_i915_private *dev_priv,
u32 reg, u32 val)
{
if (dev_priv->info->gen >= 6)
__gen6_gt_wait_for_fifo(dev_priv);
I915_WRITE(reg, val);
}
#endif #endif
...@@ -2673,6 +2673,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, ...@@ -2673,6 +2673,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
update: update:
obj->tiling_changed = false; obj->tiling_changed = false;
switch (INTEL_INFO(dev)->gen) { switch (INTEL_INFO(dev)->gen) {
case 7:
case 6: case 6:
ret = sandybridge_write_fence_reg(obj, pipelined); ret = sandybridge_write_fence_reg(obj, pipelined);
break; break;
...@@ -2706,6 +2707,7 @@ i915_gem_clear_fence_reg(struct drm_device *dev, ...@@ -2706,6 +2707,7 @@ i915_gem_clear_fence_reg(struct drm_device *dev,
uint32_t fence_reg = reg - dev_priv->fence_regs; uint32_t fence_reg = reg - dev_priv->fence_regs;
switch (INTEL_INFO(dev)->gen) { switch (INTEL_INFO(dev)->gen) {
case 7:
case 6: case 6:
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0); I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0);
break; break;
...@@ -2878,6 +2880,17 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj) ...@@ -2878,6 +2880,17 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj)
if (obj->pages == NULL) if (obj->pages == NULL)
return; return;
/* If the GPU is snooping the contents of the CPU cache,
* we do not need to manually clear the CPU cache lines. However,
* the caches are only snooped when the render cache is
* flushed/invalidated. As we always have to emit invalidations
* and flushes when moving into and out of the RENDER domain, correct
* snooping behaviour occurs naturally as the result of our domain
* tracking.
*/
if (obj->cache_level != I915_CACHE_NONE)
return;
trace_i915_gem_object_clflush(obj); trace_i915_gem_object_clflush(obj);
drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE); drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE);
...@@ -3569,7 +3582,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, ...@@ -3569,7 +3582,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
obj->base.write_domain = I915_GEM_DOMAIN_CPU; obj->base.write_domain = I915_GEM_DOMAIN_CPU;
obj->base.read_domains = I915_GEM_DOMAIN_CPU; obj->base.read_domains = I915_GEM_DOMAIN_CPU;
obj->agp_type = AGP_USER_MEMORY; obj->cache_level = I915_CACHE_NONE;
obj->base.driver_private = NULL; obj->base.driver_private = NULL;
obj->fence_reg = I915_FENCE_REG_NONE; obj->fence_reg = I915_FENCE_REG_NONE;
INIT_LIST_HEAD(&obj->mm_list); INIT_LIST_HEAD(&obj->mm_list);
...@@ -3845,25 +3858,10 @@ i915_gem_load(struct drm_device *dev) ...@@ -3845,25 +3858,10 @@ i915_gem_load(struct drm_device *dev)
dev_priv->num_fence_regs = 8; dev_priv->num_fence_regs = 8;
/* Initialize fence registers to zero */ /* Initialize fence registers to zero */
switch (INTEL_INFO(dev)->gen) { for (i = 0; i < dev_priv->num_fence_regs; i++) {
case 6: i915_gem_clear_fence_reg(dev, &dev_priv->fence_regs[i]);
for (i = 0; i < 16; i++)
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0);
break;
case 5:
case 4:
for (i = 0; i < 16; i++)
I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
break;
case 3:
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
for (i = 0; i < 8; i++)
I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
case 2:
for (i = 0; i < 8; i++)
I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
break;
} }
i915_gem_detect_bit_6_swizzle(dev); i915_gem_detect_bit_6_swizzle(dev);
init_waitqueue_head(&dev_priv->pending_flip_queue); init_waitqueue_head(&dev_priv->pending_flip_queue);
......
...@@ -29,6 +29,26 @@ ...@@ -29,6 +29,26 @@
#include "i915_trace.h" #include "i915_trace.h"
#include "intel_drv.h" #include "intel_drv.h"
/* XXX kill agp_type! */
static unsigned int cache_level_to_agp_type(struct drm_device *dev,
enum i915_cache_level cache_level)
{
switch (cache_level) {
case I915_CACHE_LLC_MLC:
if (INTEL_INFO(dev)->gen >= 6)
return AGP_USER_CACHED_MEMORY_LLC_MLC;
/* Older chipsets do not have this extra level of CPU
* cacheing, so fallthrough and request the PTE simply
* as cached.
*/
case I915_CACHE_LLC:
return AGP_USER_CACHED_MEMORY;
default:
case I915_CACHE_NONE:
return AGP_USER_MEMORY;
}
}
void i915_gem_restore_gtt_mappings(struct drm_device *dev) void i915_gem_restore_gtt_mappings(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -39,6 +59,9 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) ...@@ -39,6 +59,9 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
(dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE); (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
unsigned int agp_type =
cache_level_to_agp_type(dev, obj->cache_level);
i915_gem_clflush_object(obj); i915_gem_clflush_object(obj);
if (dev_priv->mm.gtt->needs_dmar) { if (dev_priv->mm.gtt->needs_dmar) {
...@@ -46,15 +69,14 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) ...@@ -46,15 +69,14 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
intel_gtt_insert_sg_entries(obj->sg_list, intel_gtt_insert_sg_entries(obj->sg_list,
obj->num_sg, obj->num_sg,
obj->gtt_space->start obj->gtt_space->start >> PAGE_SHIFT,
>> PAGE_SHIFT, agp_type);
obj->agp_type);
} else } else
intel_gtt_insert_pages(obj->gtt_space->start intel_gtt_insert_pages(obj->gtt_space->start
>> PAGE_SHIFT, >> PAGE_SHIFT,
obj->base.size >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT,
obj->pages, obj->pages,
obj->agp_type); agp_type);
} }
intel_gtt_chipset_flush(); intel_gtt_chipset_flush();
...@@ -64,6 +86,7 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) ...@@ -64,6 +86,7 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
{ {
struct drm_device *dev = obj->base.dev; struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
unsigned int agp_type = cache_level_to_agp_type(dev, obj->cache_level);
int ret; int ret;
if (dev_priv->mm.gtt->needs_dmar) { if (dev_priv->mm.gtt->needs_dmar) {
...@@ -77,12 +100,12 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) ...@@ -77,12 +100,12 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
intel_gtt_insert_sg_entries(obj->sg_list, intel_gtt_insert_sg_entries(obj->sg_list,
obj->num_sg, obj->num_sg,
obj->gtt_space->start >> PAGE_SHIFT, obj->gtt_space->start >> PAGE_SHIFT,
obj->agp_type); agp_type);
} else } else
intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT, intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
obj->base.size >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT,
obj->pages, obj->pages,
obj->agp_type); agp_type);
return 0; return 0;
} }
......
...@@ -92,7 +92,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) ...@@ -92,7 +92,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
if (IS_GEN5(dev) || IS_GEN6(dev)) { if (INTEL_INFO(dev)->gen >= 5) {
/* On Ironlake whatever DRAM config, GPU always do /* On Ironlake whatever DRAM config, GPU always do
* same swizzling setup. * same swizzling setup.
*/ */
......
...@@ -367,22 +367,30 @@ static void notify_ring(struct drm_device *dev, ...@@ -367,22 +367,30 @@ static void notify_ring(struct drm_device *dev,
jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
} }
static void gen6_pm_irq_handler(struct drm_device *dev) static void gen6_pm_rps_work(struct work_struct *work)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
rps_work);
u8 new_delay = dev_priv->cur_delay; u8 new_delay = dev_priv->cur_delay;
u32 pm_iir; u32 pm_iir, pm_imr;
spin_lock_irq(&dev_priv->rps_lock);
pm_iir = dev_priv->pm_iir;
dev_priv->pm_iir = 0;
pm_imr = I915_READ(GEN6_PMIMR);
spin_unlock_irq(&dev_priv->rps_lock);
pm_iir = I915_READ(GEN6_PMIIR);
if (!pm_iir) if (!pm_iir)
return; return;
mutex_lock(&dev_priv->dev->struct_mutex);
if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
if (dev_priv->cur_delay != dev_priv->max_delay) if (dev_priv->cur_delay != dev_priv->max_delay)
new_delay = dev_priv->cur_delay + 1; new_delay = dev_priv->cur_delay + 1;
if (new_delay > dev_priv->max_delay) if (new_delay > dev_priv->max_delay)
new_delay = dev_priv->max_delay; new_delay = dev_priv->max_delay;
} else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) { } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) {
gen6_gt_force_wake_get(dev_priv);
if (dev_priv->cur_delay != dev_priv->min_delay) if (dev_priv->cur_delay != dev_priv->min_delay)
new_delay = dev_priv->cur_delay - 1; new_delay = dev_priv->cur_delay - 1;
if (new_delay < dev_priv->min_delay) { if (new_delay < dev_priv->min_delay) {
...@@ -396,13 +404,19 @@ static void gen6_pm_irq_handler(struct drm_device *dev) ...@@ -396,13 +404,19 @@ static void gen6_pm_irq_handler(struct drm_device *dev)
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000); I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000);
} }
gen6_gt_force_wake_put(dev_priv);
} }
gen6_set_rps(dev, new_delay); gen6_set_rps(dev_priv->dev, new_delay);
dev_priv->cur_delay = new_delay; dev_priv->cur_delay = new_delay;
I915_WRITE(GEN6_PMIIR, pm_iir); /*
* rps_lock not held here because clearing is non-destructive. There is
* an *extremely* unlikely race with gen6_rps_enable() that is prevented
* by holding struct_mutex for the duration of the write.
*/
I915_WRITE(GEN6_PMIMR, pm_imr & ~pm_iir);
mutex_unlock(&dev_priv->dev->struct_mutex);
} }
static void pch_irq_handler(struct drm_device *dev) static void pch_irq_handler(struct drm_device *dev)
...@@ -448,8 +462,97 @@ static void pch_irq_handler(struct drm_device *dev) ...@@ -448,8 +462,97 @@ static void pch_irq_handler(struct drm_device *dev)
DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
} }
static irqreturn_t ironlake_irq_handler(struct drm_device *dev) irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = IRQ_NONE;
u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
struct drm_i915_master_private *master_priv;
atomic_inc(&dev_priv->irq_received);
/* disable master interrupt before clearing iir */
de_ier = I915_READ(DEIER);
I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
POSTING_READ(DEIER);
de_iir = I915_READ(DEIIR);
gt_iir = I915_READ(GTIIR);
pch_iir = I915_READ(SDEIIR);
pm_iir = I915_READ(GEN6_PMIIR);
if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0)
goto done;
ret = IRQ_HANDLED;
if (dev->primary->master) {
master_priv = dev->primary->master->driver_priv;
if (master_priv->sarea_priv)
master_priv->sarea_priv->last_dispatch =
READ_BREADCRUMB(dev_priv);
}
if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
notify_ring(dev, &dev_priv->ring[RCS]);
if (gt_iir & GT_GEN6_BSD_USER_INTERRUPT)
notify_ring(dev, &dev_priv->ring[VCS]);
if (gt_iir & GT_BLT_USER_INTERRUPT)
notify_ring(dev, &dev_priv->ring[BCS]);
if (de_iir & DE_GSE_IVB)
intel_opregion_gse_intr(dev);
if (de_iir & DE_PLANEA_FLIP_DONE_IVB) {
intel_prepare_page_flip(dev, 0);
intel_finish_page_flip_plane(dev, 0);
}
if (de_iir & DE_PLANEB_FLIP_DONE_IVB) {
intel_prepare_page_flip(dev, 1);
intel_finish_page_flip_plane(dev, 1);
}
if (de_iir & DE_PIPEA_VBLANK_IVB)
drm_handle_vblank(dev, 0);
if (de_iir & DE_PIPEB_VBLANK_IVB);
drm_handle_vblank(dev, 1);
/* check event from PCH */
if (de_iir & DE_PCH_EVENT_IVB) {
if (pch_iir & SDE_HOTPLUG_MASK_CPT)
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
pch_irq_handler(dev);
}
if (pm_iir & GEN6_PM_DEFERRED_EVENTS) {
unsigned long flags;
spin_lock_irqsave(&dev_priv->rps_lock, flags);
WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
I915_WRITE(GEN6_PMIMR, pm_iir);
dev_priv->pm_iir |= pm_iir;
spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
queue_work(dev_priv->wq, &dev_priv->rps_work);
}
/* should clear PCH hotplug event before clear CPU irq */
I915_WRITE(SDEIIR, pch_iir);
I915_WRITE(GTIIR, gt_iir);
I915_WRITE(DEIIR, de_iir);
I915_WRITE(GEN6_PMIIR, pm_iir);
done:
I915_WRITE(DEIER, de_ier);
POSTING_READ(DEIER);
return ret;
}
irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
{ {
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = IRQ_NONE; int ret = IRQ_NONE;
u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
...@@ -457,6 +560,8 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) ...@@ -457,6 +560,8 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
struct drm_i915_master_private *master_priv; struct drm_i915_master_private *master_priv;
u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT; u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
atomic_inc(&dev_priv->irq_received);
if (IS_GEN6(dev)) if (IS_GEN6(dev))
bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT; bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
...@@ -526,13 +631,30 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) ...@@ -526,13 +631,30 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
i915_handle_rps_change(dev); i915_handle_rps_change(dev);
} }
if (IS_GEN6(dev)) if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) {
gen6_pm_irq_handler(dev); /*
* IIR bits should never already be set because IMR should
* prevent an interrupt from being shown in IIR. The warning
* displays a case where we've unsafely cleared
* dev_priv->pm_iir. Although missing an interrupt of the same
* type is not a problem, it displays a problem in the logic.
*
* The mask bit in IMR is cleared by rps_work.
*/
unsigned long flags;
spin_lock_irqsave(&dev_priv->rps_lock, flags);
WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
I915_WRITE(GEN6_PMIMR, pm_iir);
dev_priv->pm_iir |= pm_iir;
spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
queue_work(dev_priv->wq, &dev_priv->rps_work);
}
/* should clear PCH hotplug event before clear CPU irq */ /* should clear PCH hotplug event before clear CPU irq */
I915_WRITE(SDEIIR, pch_iir); I915_WRITE(SDEIIR, pch_iir);
I915_WRITE(GTIIR, gt_iir); I915_WRITE(GTIIR, gt_iir);
I915_WRITE(DEIIR, de_iir); I915_WRITE(DEIIR, de_iir);
I915_WRITE(GEN6_PMIIR, pm_iir);
done: done:
I915_WRITE(DEIER, de_ier); I915_WRITE(DEIER, de_ier);
...@@ -676,7 +798,7 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err, ...@@ -676,7 +798,7 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err,
err->dirty = obj->dirty; err->dirty = obj->dirty;
err->purgeable = obj->madv != I915_MADV_WILLNEED; err->purgeable = obj->madv != I915_MADV_WILLNEED;
err->ring = obj->ring ? obj->ring->id : 0; err->ring = obj->ring ? obj->ring->id : 0;
err->agp_type = obj->agp_type == AGP_USER_CACHED_MEMORY; err->cache_level = obj->cache_level;
if (++i == count) if (++i == count)
break; break;
...@@ -1103,9 +1225,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -1103,9 +1225,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
atomic_inc(&dev_priv->irq_received); atomic_inc(&dev_priv->irq_received);
if (HAS_PCH_SPLIT(dev))
return ironlake_irq_handler(dev);
iir = I915_READ(IIR); iir = I915_READ(IIR);
if (INTEL_INFO(dev)->gen >= 4) if (INTEL_INFO(dev)->gen >= 4)
...@@ -1344,10 +1463,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) ...@@ -1344,10 +1463,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
if (HAS_PCH_SPLIT(dev)) if (INTEL_INFO(dev)->gen >= 4)
ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
else if (INTEL_INFO(dev)->gen >= 4)
i915_enable_pipestat(dev_priv, pipe, i915_enable_pipestat(dev_priv, pipe,
PIPE_START_VBLANK_INTERRUPT_ENABLE); PIPE_START_VBLANK_INTERRUPT_ENABLE);
else else
...@@ -1362,6 +1478,38 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) ...@@ -1362,6 +1478,38 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
return 0; return 0;
} }
int ironlake_enable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
if (!i915_pipe_enabled(dev, pipe))
return -EINVAL;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
return 0;
}
int ivybridge_enable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
if (!i915_pipe_enabled(dev, pipe))
return -EINVAL;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
return 0;
}
/* Called from drm generic code, passed 'crtc' which /* Called from drm generic code, passed 'crtc' which
* we use as a pipe index * we use as a pipe index
*/ */
...@@ -1375,13 +1523,31 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) ...@@ -1375,13 +1523,31 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
I915_WRITE(INSTPM, I915_WRITE(INSTPM,
INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS); INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS);
if (HAS_PCH_SPLIT(dev)) i915_disable_pipestat(dev_priv, pipe,
ironlake_disable_display_irq(dev_priv, (pipe == 0) ? PIPE_VBLANK_INTERRUPT_ENABLE |
DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); PIPE_START_VBLANK_INTERRUPT_ENABLE);
else spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
i915_disable_pipestat(dev_priv, pipe, }
PIPE_VBLANK_INTERRUPT_ENABLE |
PIPE_START_VBLANK_INTERRUPT_ENABLE); void ironlake_disable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
void ivybridge_disable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
} }
...@@ -1562,10 +1728,17 @@ void i915_hangcheck_elapsed(unsigned long data) ...@@ -1562,10 +1728,17 @@ void i915_hangcheck_elapsed(unsigned long data)
/* drm_dma.h hooks /* drm_dma.h hooks
*/ */
static void ironlake_irq_preinstall(struct drm_device *dev) void ironlake_irq_preinstall(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
atomic_set(&dev_priv->irq_received, 0);
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
INIT_WORK(&dev_priv->error_work, i915_error_work_func);
if (IS_GEN6(dev) || IS_IVYBRIDGE(dev))
INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
I915_WRITE(HWSTAM, 0xeffe); I915_WRITE(HWSTAM, 0xeffe);
/* XXX hotplug from PCH */ /* XXX hotplug from PCH */
...@@ -1585,7 +1758,7 @@ static void ironlake_irq_preinstall(struct drm_device *dev) ...@@ -1585,7 +1758,7 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
POSTING_READ(SDEIER); POSTING_READ(SDEIER);
} }
static int ironlake_irq_postinstall(struct drm_device *dev) int ironlake_irq_postinstall(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
/* enable kind of interrupts always enabled */ /* enable kind of interrupts always enabled */
...@@ -1594,6 +1767,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev) ...@@ -1594,6 +1767,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
u32 render_irqs; u32 render_irqs;
u32 hotplug_mask; u32 hotplug_mask;
DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
if (HAS_BSD(dev))
DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
if (HAS_BLT(dev))
DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
dev_priv->irq_mask = ~display_mask; dev_priv->irq_mask = ~display_mask;
/* should always can generate irq */ /* should always can generate irq */
...@@ -1650,6 +1830,56 @@ static int ironlake_irq_postinstall(struct drm_device *dev) ...@@ -1650,6 +1830,56 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
return 0; return 0;
} }
int ivybridge_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
/* enable kind of interrupts always enabled */
u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB |
DE_PLANEB_FLIP_DONE_IVB;
u32 render_irqs;
u32 hotplug_mask;
DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
if (HAS_BSD(dev))
DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
if (HAS_BLT(dev))
DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
dev_priv->irq_mask = ~display_mask;
/* should always can generate irq */
I915_WRITE(DEIIR, I915_READ(DEIIR));
I915_WRITE(DEIMR, dev_priv->irq_mask);
I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB |
DE_PIPEB_VBLANK_IVB);
POSTING_READ(DEIER);
dev_priv->gt_irq_mask = ~0;
I915_WRITE(GTIIR, I915_READ(GTIIR));
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT |
GT_BLT_USER_INTERRUPT;
I915_WRITE(GTIER, render_irqs);
POSTING_READ(GTIER);
hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
SDE_PORTB_HOTPLUG_CPT |
SDE_PORTC_HOTPLUG_CPT |
SDE_PORTD_HOTPLUG_CPT);
dev_priv->pch_irq_mask = ~hotplug_mask;
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
I915_WRITE(SDEIMR, dev_priv->pch_irq_mask);
I915_WRITE(SDEIER, hotplug_mask);
POSTING_READ(SDEIER);
return 0;
}
void i915_driver_irq_preinstall(struct drm_device * dev) void i915_driver_irq_preinstall(struct drm_device * dev)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
...@@ -1660,11 +1890,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev) ...@@ -1660,11 +1890,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
INIT_WORK(&dev_priv->error_work, i915_error_work_func); INIT_WORK(&dev_priv->error_work, i915_error_work_func);
if (HAS_PCH_SPLIT(dev)) {
ironlake_irq_preinstall(dev);
return;
}
if (I915_HAS_HOTPLUG(dev)) { if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
...@@ -1688,17 +1913,8 @@ int i915_driver_irq_postinstall(struct drm_device *dev) ...@@ -1688,17 +1913,8 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
u32 error_mask; u32 error_mask;
DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
if (HAS_BSD(dev))
DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
if (HAS_BLT(dev))
DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
if (HAS_PCH_SPLIT(dev))
return ironlake_irq_postinstall(dev);
/* Unmask the interrupts that we always want on. */ /* Unmask the interrupts that we always want on. */
dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX; dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX;
...@@ -1767,9 +1983,15 @@ int i915_driver_irq_postinstall(struct drm_device *dev) ...@@ -1767,9 +1983,15 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
return 0; return 0;
} }
static void ironlake_irq_uninstall(struct drm_device *dev) void ironlake_irq_uninstall(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
if (!dev_priv)
return;
dev_priv->vblank_pipe = 0;
I915_WRITE(HWSTAM, 0xffffffff); I915_WRITE(HWSTAM, 0xffffffff);
I915_WRITE(DEIMR, 0xffffffff); I915_WRITE(DEIMR, 0xffffffff);
...@@ -1791,11 +2013,6 @@ void i915_driver_irq_uninstall(struct drm_device * dev) ...@@ -1791,11 +2013,6 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
dev_priv->vblank_pipe = 0; dev_priv->vblank_pipe = 0;
if (HAS_PCH_SPLIT(dev)) {
ironlake_irq_uninstall(dev);
return;
}
if (I915_HAS_HOTPLUG(dev)) { if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
......
...@@ -291,6 +291,9 @@ ...@@ -291,6 +291,9 @@
#define RING_MAX_IDLE(base) ((base)+0x54) #define RING_MAX_IDLE(base) ((base)+0x54)
#define RING_HWS_PGA(base) ((base)+0x80) #define RING_HWS_PGA(base) ((base)+0x80)
#define RING_HWS_PGA_GEN6(base) ((base)+0x2080) #define RING_HWS_PGA_GEN6(base) ((base)+0x2080)
#define RENDER_HWS_PGA_GEN7 (0x04080)
#define BSD_HWS_PGA_GEN7 (0x04180)
#define BLT_HWS_PGA_GEN7 (0x04280)
#define RING_ACTHD(base) ((base)+0x74) #define RING_ACTHD(base) ((base)+0x74)
#define RING_NOPID(base) ((base)+0x94) #define RING_NOPID(base) ((base)+0x94)
#define RING_IMR(base) ((base)+0xa8) #define RING_IMR(base) ((base)+0xa8)
...@@ -2778,6 +2781,19 @@ ...@@ -2778,6 +2781,19 @@
#define DE_PIPEA_VSYNC (1 << 3) #define DE_PIPEA_VSYNC (1 << 3)
#define DE_PIPEA_FIFO_UNDERRUN (1 << 0) #define DE_PIPEA_FIFO_UNDERRUN (1 << 0)
/* More Ivybridge lolz */
#define DE_ERR_DEBUG_IVB (1<<30)
#define DE_GSE_IVB (1<<29)
#define DE_PCH_EVENT_IVB (1<<28)
#define DE_DP_A_HOTPLUG_IVB (1<<27)
#define DE_AUX_CHANNEL_A_IVB (1<<26)
#define DE_SPRITEB_FLIP_DONE_IVB (1<<9)
#define DE_SPRITEA_FLIP_DONE_IVB (1<<4)
#define DE_PLANEB_FLIP_DONE_IVB (1<<8)
#define DE_PLANEA_FLIP_DONE_IVB (1<<3)
#define DE_PIPEB_VBLANK_IVB (1<<5)
#define DE_PIPEA_VBLANK_IVB (1<<0)
#define DEISR 0x44000 #define DEISR 0x44000
#define DEIMR 0x44004 #define DEIMR 0x44004
#define DEIIR 0x44008 #define DEIIR 0x44008
...@@ -2809,6 +2825,7 @@ ...@@ -2809,6 +2825,7 @@
#define ILK_eDP_A_DISABLE (1<<24) #define ILK_eDP_A_DISABLE (1<<24)
#define ILK_DESKTOP (1<<23) #define ILK_DESKTOP (1<<23)
#define ILK_DSPCLK_GATE 0x42020 #define ILK_DSPCLK_GATE 0x42020
#define IVB_VRHUNIT_CLK_GATE (1<<28)
#define ILK_DPARB_CLK_GATE (1<<5) #define ILK_DPARB_CLK_GATE (1<<5)
#define ILK_DPFD_CLK_GATE (1<<7) #define ILK_DPFD_CLK_GATE (1<<7)
...@@ -3057,6 +3074,9 @@ ...@@ -3057,6 +3074,9 @@
#define TRANS_6BPC (2<<5) #define TRANS_6BPC (2<<5)
#define TRANS_12BPC (3<<5) #define TRANS_12BPC (3<<5)
#define SOUTH_CHICKEN2 0xc2004
#define DPLS_EDP_PPS_FIX_DIS (1<<0)
#define _FDI_RXA_CHICKEN 0xc200c #define _FDI_RXA_CHICKEN 0xc200c
#define _FDI_RXB_CHICKEN 0xc2010 #define _FDI_RXB_CHICKEN 0xc2010
#define FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1) #define FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1)
...@@ -3104,7 +3124,15 @@ ...@@ -3104,7 +3124,15 @@
#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18) #define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18)
/* Ironlake: hardwired to 1 */ /* Ironlake: hardwired to 1 */
#define FDI_TX_PLL_ENABLE (1<<14) #define FDI_TX_PLL_ENABLE (1<<14)
/* Ivybridge has different bits for lolz */
#define FDI_LINK_TRAIN_PATTERN_1_IVB (0<<8)
#define FDI_LINK_TRAIN_PATTERN_2_IVB (1<<8)
#define FDI_LINK_TRAIN_PATTERN_IDLE_IVB (2<<8)
#define FDI_LINK_TRAIN_NONE_IVB (3<<8)
/* both Tx and Rx */ /* both Tx and Rx */
#define FDI_LINK_TRAIN_AUTO (1<<10)
#define FDI_SCRAMBLING_ENABLE (0<<7) #define FDI_SCRAMBLING_ENABLE (0<<7)
#define FDI_SCRAMBLING_DISABLE (1<<7) #define FDI_SCRAMBLING_DISABLE (1<<7)
...@@ -3114,6 +3142,8 @@ ...@@ -3114,6 +3142,8 @@
#define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL) #define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
#define FDI_RX_ENABLE (1<<31) #define FDI_RX_ENABLE (1<<31)
/* train, dp width same as FDI_TX */ /* train, dp width same as FDI_TX */
#define FDI_FS_ERRC_ENABLE (1<<27)
#define FDI_FE_ERRC_ENABLE (1<<26)
#define FDI_DP_PORT_WIDTH_X8 (7<<19) #define FDI_DP_PORT_WIDTH_X8 (7<<19)
#define FDI_8BPC (0<<16) #define FDI_8BPC (0<<16)
#define FDI_10BPC (1<<16) #define FDI_10BPC (1<<16)
...@@ -3386,7 +3416,7 @@ ...@@ -3386,7 +3416,7 @@
#define GEN6_PMINTRMSK 0xA168 #define GEN6_PMINTRMSK 0xA168
#define GEN6_PMISR 0x44020 #define GEN6_PMISR 0x44020
#define GEN6_PMIMR 0x44024 #define GEN6_PMIMR 0x44024 /* rps_lock */
#define GEN6_PMIIR 0x44028 #define GEN6_PMIIR 0x44028
#define GEN6_PMIER 0x4402C #define GEN6_PMIER 0x4402C
#define GEN6_PM_MBOX_EVENT (1<<25) #define GEN6_PM_MBOX_EVENT (1<<25)
...@@ -3396,6 +3426,9 @@ ...@@ -3396,6 +3426,9 @@
#define GEN6_PM_RP_DOWN_THRESHOLD (1<<4) #define GEN6_PM_RP_DOWN_THRESHOLD (1<<4)
#define GEN6_PM_RP_UP_EI_EXPIRED (1<<2) #define GEN6_PM_RP_UP_EI_EXPIRED (1<<2)
#define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1) #define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1)
#define GEN6_PM_DEFERRED_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \
GEN6_PM_RP_DOWN_THRESHOLD | \
GEN6_PM_RP_DOWN_TIMEOUT)
#define GEN6_PCODE_MAILBOX 0x138124 #define GEN6_PCODE_MAILBOX 0x138124
#define GEN6_PCODE_READY (1<<31) #define GEN6_PCODE_READY (1<<31)
......
...@@ -863,8 +863,7 @@ int i915_restore_state(struct drm_device *dev) ...@@ -863,8 +863,7 @@ int i915_restore_state(struct drm_device *dev)
I915_WRITE(IMR, dev_priv->saveIMR); I915_WRITE(IMR, dev_priv->saveIMR);
} }
/* Clock gating state */ intel_init_clock_gating(dev);
intel_enable_clock_gating(dev);
if (IS_IRONLAKE_M(dev)) { if (IS_IRONLAKE_M(dev)) {
ironlake_enable_drps(dev); ironlake_enable_drps(dev);
......
...@@ -214,9 +214,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, ...@@ -214,9 +214,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
i915_lvds_downclock) { i915_lvds_downclock) {
dev_priv->lvds_downclock_avail = 1; dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = temp_downclock; dev_priv->lvds_downclock = temp_downclock;
DRM_DEBUG_KMS("LVDS downclock is found in VBT. ", DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
"Normal Clock %dKHz, downclock %dKHz\n", "Normal Clock %dKHz, downclock %dKHz\n",
temp_downclock, panel_fixed_mode->clock); temp_downclock, panel_fixed_mode->clock);
} }
return; return;
} }
......
...@@ -305,13 +305,11 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) ...@@ -305,13 +305,11 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
} }
static enum drm_connector_status static enum drm_connector_status
intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt) intel_crt_load_detect(struct intel_crt *crt)
{ {
struct drm_encoder *encoder = &crt->base.base; struct drm_device *dev = crt->base.base.dev;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe;
uint32_t pipe = intel_crtc->pipe;
uint32_t save_bclrpat; uint32_t save_bclrpat;
uint32_t save_vtotal; uint32_t save_vtotal;
uint32_t vtotal, vactive; uint32_t vtotal, vactive;
...@@ -432,7 +430,6 @@ intel_crt_detect(struct drm_connector *connector, bool force) ...@@ -432,7 +430,6 @@ intel_crt_detect(struct drm_connector *connector, bool force)
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct intel_crt *crt = intel_attached_crt(connector); struct intel_crt *crt = intel_attached_crt(connector);
struct drm_crtc *crtc; struct drm_crtc *crtc;
int dpms_mode;
enum drm_connector_status status; enum drm_connector_status status;
if (I915_HAS_HOTPLUG(dev)) { if (I915_HAS_HOTPLUG(dev)) {
...@@ -454,17 +451,18 @@ intel_crt_detect(struct drm_connector *connector, bool force) ...@@ -454,17 +451,18 @@ intel_crt_detect(struct drm_connector *connector, bool force)
/* for pre-945g platforms use load detect */ /* for pre-945g platforms use load detect */
crtc = crt->base.base.crtc; crtc = crt->base.base.crtc;
if (crtc && crtc->enabled) { if (crtc && crtc->enabled) {
status = intel_crt_load_detect(crtc, crt); status = intel_crt_load_detect(crt);
} else { } else {
crtc = intel_get_load_detect_pipe(&crt->base, connector, struct intel_load_detect_pipe tmp;
NULL, &dpms_mode);
if (crtc) { if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
&tmp)) {
if (intel_crt_detect_ddc(connector)) if (intel_crt_detect_ddc(connector))
status = connector_status_connected; status = connector_status_connected;
else else
status = intel_crt_load_detect(crtc, crt); status = intel_crt_load_detect(crt);
intel_release_load_detect_pipe(&crt->base, intel_release_load_detect_pipe(&crt->base, connector,
connector, dpms_mode); &tmp);
} else } else
status = connector_status_unknown; status = connector_status_unknown;
} }
......
此差异已折叠。
...@@ -2544,21 +2544,19 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) ...@@ -2544,21 +2544,19 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
if (!intel_sdvo) if (!intel_sdvo)
return false; return false;
intel_sdvo->sdvo_reg = sdvo_reg;
intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) { if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {
kfree(intel_sdvo); kfree(intel_sdvo);
return false; return false;
} }
intel_sdvo->sdvo_reg = sdvo_reg; /* encoder type will be decided later */
intel_encoder = &intel_sdvo->base; intel_encoder = &intel_sdvo->base;
intel_encoder->type = INTEL_OUTPUT_SDVO; intel_encoder->type = INTEL_OUTPUT_SDVO;
/* encoder type will be decided later */
drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0); drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
/* Read the regs to test if we can talk to the device */ /* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) { for (i = 0; i < 0x40; i++) {
u8 byte; u8 byte;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -42,3 +42,4 @@ obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o ...@@ -42,3 +42,4 @@ obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o
obj-$(CONFIG_IBM_RTL) += ibm_rtl.o obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册