drm/i915: Add support for VGA load detection (pre-945).
Two approaches for VGA detections: hot plug detection for 945G onwards and load pipe detection for Pre-945G. Load pipe detection will get one free pipe, set border color as red and blue, then check CRT status by swf register. This is a sync-up with the 2D driver. Signed-off-by: Ma Ling <ling.ma@intel.com> Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
parent
619ac3b75a
commit
e4a5d54f92
|
@ -198,9 +198,142 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
|
||||||
return intel_ddc_probe(intel_output);
|
return intel_ddc_probe(intel_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum drm_connector_status
|
||||||
|
intel_crt_load_detect(struct drm_crtc *crtc, struct intel_output *intel_output)
|
||||||
|
{
|
||||||
|
struct drm_encoder *encoder = &intel_output->enc;
|
||||||
|
struct drm_device *dev = encoder->dev;
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||||
|
uint32_t pipe = intel_crtc->pipe;
|
||||||
|
uint32_t save_bclrpat;
|
||||||
|
uint32_t save_vtotal;
|
||||||
|
uint32_t vtotal, vactive;
|
||||||
|
uint32_t vsample;
|
||||||
|
uint32_t vblank, vblank_start, vblank_end;
|
||||||
|
uint32_t dsl;
|
||||||
|
uint32_t bclrpat_reg;
|
||||||
|
uint32_t vtotal_reg;
|
||||||
|
uint32_t vblank_reg;
|
||||||
|
uint32_t vsync_reg;
|
||||||
|
uint32_t pipeconf_reg;
|
||||||
|
uint32_t pipe_dsl_reg;
|
||||||
|
uint8_t st00;
|
||||||
|
enum drm_connector_status status;
|
||||||
|
|
||||||
|
if (pipe == 0) {
|
||||||
|
bclrpat_reg = BCLRPAT_A;
|
||||||
|
vtotal_reg = VTOTAL_A;
|
||||||
|
vblank_reg = VBLANK_A;
|
||||||
|
vsync_reg = VSYNC_A;
|
||||||
|
pipeconf_reg = PIPEACONF;
|
||||||
|
pipe_dsl_reg = PIPEADSL;
|
||||||
|
} else {
|
||||||
|
bclrpat_reg = BCLRPAT_B;
|
||||||
|
vtotal_reg = VTOTAL_B;
|
||||||
|
vblank_reg = VBLANK_B;
|
||||||
|
vsync_reg = VSYNC_B;
|
||||||
|
pipeconf_reg = PIPEBCONF;
|
||||||
|
pipe_dsl_reg = PIPEBDSL;
|
||||||
|
}
|
||||||
|
|
||||||
|
save_bclrpat = I915_READ(bclrpat_reg);
|
||||||
|
save_vtotal = I915_READ(vtotal_reg);
|
||||||
|
vblank = I915_READ(vblank_reg);
|
||||||
|
|
||||||
|
vtotal = ((save_vtotal >> 16) & 0xfff) + 1;
|
||||||
|
vactive = (save_vtotal & 0x7ff) + 1;
|
||||||
|
|
||||||
|
vblank_start = (vblank & 0xfff) + 1;
|
||||||
|
vblank_end = ((vblank >> 16) & 0xfff) + 1;
|
||||||
|
|
||||||
|
/* Set the border color to purple. */
|
||||||
|
I915_WRITE(bclrpat_reg, 0x500050);
|
||||||
|
|
||||||
|
if (IS_I9XX(dev)) {
|
||||||
|
uint32_t pipeconf = I915_READ(pipeconf_reg);
|
||||||
|
I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
|
||||||
|
/* Wait for next Vblank to substitue
|
||||||
|
* border color for Color info */
|
||||||
|
intel_wait_for_vblank(dev);
|
||||||
|
st00 = I915_READ8(VGA_MSR_WRITE);
|
||||||
|
status = ((st00 & (1 << 4)) != 0) ?
|
||||||
|
connector_status_connected :
|
||||||
|
connector_status_disconnected;
|
||||||
|
|
||||||
|
I915_WRITE(pipeconf_reg, pipeconf);
|
||||||
|
} else {
|
||||||
|
bool restore_vblank = false;
|
||||||
|
int count, detect;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there isn't any border, add some.
|
||||||
|
* Yes, this will flicker
|
||||||
|
*/
|
||||||
|
if (vblank_start <= vactive && vblank_end >= vtotal) {
|
||||||
|
uint32_t vsync = I915_READ(vsync_reg);
|
||||||
|
uint32_t vsync_start = (vsync & 0xffff) + 1;
|
||||||
|
|
||||||
|
vblank_start = vsync_start;
|
||||||
|
I915_WRITE(vblank_reg,
|
||||||
|
(vblank_start - 1) |
|
||||||
|
((vblank_end - 1) << 16));
|
||||||
|
restore_vblank = true;
|
||||||
|
}
|
||||||
|
/* sample in the vertical border, selecting the larger one */
|
||||||
|
if (vblank_start - vactive >= vtotal - vblank_end)
|
||||||
|
vsample = (vblank_start + vactive) >> 1;
|
||||||
|
else
|
||||||
|
vsample = (vtotal + vblank_end) >> 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for the border to be displayed
|
||||||
|
*/
|
||||||
|
while (I915_READ(pipe_dsl_reg) >= vactive)
|
||||||
|
;
|
||||||
|
while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample)
|
||||||
|
;
|
||||||
|
/*
|
||||||
|
* Watch ST00 for an entire scanline
|
||||||
|
*/
|
||||||
|
detect = 0;
|
||||||
|
count = 0;
|
||||||
|
do {
|
||||||
|
count++;
|
||||||
|
/* Read the ST00 VGA status register */
|
||||||
|
st00 = I915_READ8(VGA_MSR_WRITE);
|
||||||
|
if (st00 & (1 << 4))
|
||||||
|
detect++;
|
||||||
|
} while ((I915_READ(pipe_dsl_reg) == dsl));
|
||||||
|
|
||||||
|
/* restore vblank if necessary */
|
||||||
|
if (restore_vblank)
|
||||||
|
I915_WRITE(vblank_reg, vblank);
|
||||||
|
/*
|
||||||
|
* If more than 3/4 of the scanline detected a monitor,
|
||||||
|
* then it is assumed to be present. This works even on i830,
|
||||||
|
* where there isn't any way to force the border color across
|
||||||
|
* the screen
|
||||||
|
*/
|
||||||
|
status = detect * 4 > count * 3 ?
|
||||||
|
connector_status_connected :
|
||||||
|
connector_status_disconnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore previous settings */
|
||||||
|
I915_WRITE(bclrpat_reg, save_bclrpat);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static enum drm_connector_status intel_crt_detect(struct drm_connector *connector)
|
static enum drm_connector_status intel_crt_detect(struct drm_connector *connector)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = connector->dev;
|
||||||
|
struct intel_output *intel_output = to_intel_output(connector);
|
||||||
|
struct drm_encoder *encoder = &intel_output->enc;
|
||||||
|
struct drm_crtc *crtc;
|
||||||
|
int dpms_mode;
|
||||||
|
enum drm_connector_status status;
|
||||||
|
|
||||||
if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
|
if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
|
||||||
if (intel_crt_detect_hotplug(connector))
|
if (intel_crt_detect_hotplug(connector))
|
||||||
|
@ -212,8 +345,20 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto
|
||||||
if (intel_crt_detect_ddc(connector))
|
if (intel_crt_detect_ddc(connector))
|
||||||
return connector_status_connected;
|
return connector_status_connected;
|
||||||
|
|
||||||
/* TODO use load detect */
|
/* for pre-945g platforms use load detect */
|
||||||
return connector_status_unknown;
|
if (encoder->crtc && encoder->crtc->enabled) {
|
||||||
|
status = intel_crt_load_detect(encoder->crtc, intel_output);
|
||||||
|
} else {
|
||||||
|
crtc = intel_get_load_detect_pipe(intel_output,
|
||||||
|
NULL, &dpms_mode);
|
||||||
|
if (crtc) {
|
||||||
|
status = intel_crt_load_detect(crtc, intel_output);
|
||||||
|
intel_release_load_detect_pipe(intel_output, dpms_mode);
|
||||||
|
} else
|
||||||
|
status = connector_status_unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intel_crt_destroy(struct drm_connector *connector)
|
static void intel_crt_destroy(struct drm_connector *connector)
|
||||||
|
|
Reference in New Issue