diff options
-rw-r--r-- | linux-core/drm_crtc.h | 1 | ||||
-rw-r--r-- | linux-core/intel_display.c | 130 | ||||
-rw-r--r-- | linux-core/intel_drv.h | 6 |
3 files changed, 135 insertions, 2 deletions
diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index ac0d2d5a..52e5ab5c 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -622,6 +622,7 @@ extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y); +extern bool drm_crtc_in_use(struct drm_crtc *crtc); extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, bool connected); extern int drm_output_attach_property(struct drm_output *output, diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 0615c1c4..13936ee2 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -567,6 +567,8 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); break; } + + intel_crtc->dpms_mode = mode; } static bool intel_crtc_lock(struct drm_crtc *crtc) @@ -1097,6 +1099,129 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, intel_crtc->lut_b[regno] = blue >> 8; } +/** + * Get a pipe with a simple mode set on it for doing load-based monitor + * detection. + * + * It will be up to the load-detect code to adjust the pipe as appropriate for + * its requirements. The pipe will be connected to no other outputs. + * + * Currently this code will only succeed if there is a pipe with no outputs + * configured for it. In the future, it could choose to temporarily disable + * some outputs to free up a pipe for its use. + * + * \return crtc, or NULL if no pipes are available. + */ + +/* VESA 640x480x72Hz mode to set on the pipe */ +static struct drm_display_mode load_detect_mode = { + DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, + 704, 832, 0, 480, 489, 491, 520, 0, V_NHSYNC | V_NVSYNC), +}; + +struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, + struct drm_display_mode *mode, + int *dpms_mode) +{ + struct drm_device *dev = output->dev; + struct intel_output *intel_output = output->driver_private; + struct intel_crtc *intel_crtc; + struct drm_crtc *possible_crtc; + struct drm_crtc *supported_crtc =NULL; + struct drm_crtc *crtc = NULL; + int i = 0; + + /* + * Algorithm gets a little messy: + * - if the output already has an assigned crtc, use it (but make + * sure it's on first) + * - try to find the first unused crtc that can drive this output, + * and use that if we find one + * - if there are no unused crtcs available, try to use the first + * one we found that supports the output + */ + + /* See if we already have a CRTC for this output */ + if (output->crtc) { + crtc = output->crtc; + /* Make sure the crtc and output are running */ + intel_crtc = crtc->driver_private; + *dpms_mode = intel_crtc->dpms_mode; + if (intel_crtc->dpms_mode != DPMSModeOn) { + crtc->funcs->dpms(crtc, DPMSModeOn); + output->funcs->dpms(output, DPMSModeOn); + } + return crtc; + } + + /* Find an unused one (if possible) */ + list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) { + i++; + if (!(output->possible_crtcs & (1 << i))) + continue; + if (!possible_crtc->enabled) { + crtc = possible_crtc; + break; + } + if (!supported_crtc) + supported_crtc = possible_crtc; + } + + /* + * If we didn't find an unused CRTC, use the first available one + * that can drive this output. + */ + if (!crtc) { + crtc = supported_crtc; + if (!crtc) + return NULL; + } + + output->crtc = crtc; + intel_output->load_detect_temp = TRUE; + + intel_crtc = crtc->driver_private; + *dpms_mode = intel_crtc->dpms_mode; + + if (!crtc->enabled) { + if (!mode) + mode = &load_detect_mode; + drm_crtc_set_mode(crtc, mode, 0, 0); + } else { + if (intel_crtc->dpms_mode != DPMSModeOn) + crtc->funcs->dpms(crtc, DPMSModeOn); + + /* Add this output to the crtc */ + output->funcs->mode_set(output, &crtc->mode, &crtc->mode); + output->funcs->commit(output); + } + /* let the output get through one full cycle before testing */ + intel_wait_for_vblank(dev); + + return crtc; +} + +void intel_release_load_detect_pipe(struct drm_output *output, int dpms_mode) +{ + struct drm_device *dev = output->dev; + struct intel_output *intel_output = output->driver_private; + struct drm_crtc *crtc = output->crtc; + + if (intel_output->load_detect_temp) { + output->crtc = NULL; + intel_output->load_detect_temp = FALSE; + crtc->enabled = drm_crtc_in_use(crtc); + drm_disable_unused_functions(dev); + } + + /* Switch crtc and output back off if necessary */ + if (crtc->enabled && dpms_mode != DPMSModeOn) { + if (output->crtc == crtc) + output->funcs->dpms(output, dpms_mode); + crtc->funcs->dpms(crtc, dpms_mode); + } +} + /* Returns the clock of the currently programmed mode of the given pipe. */ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) { @@ -1246,6 +1371,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) } intel_crtc->cursor_addr = 0; + intel_crtc->dpms_mode = DPMSModeOff; crtc->driver_private = intel_crtc; } @@ -1292,10 +1418,10 @@ static void intel_setup_outputs(struct drm_device *dev) intel_sdvo_init(dev, SDVOB); intel_sdvo_init(dev, SDVOC); } -#if 0 + if (IS_I9XX(dev) && !IS_I915G(dev)) intel_tv_init(dev); -#endif + list_for_each_entry(output, &dev->mode_config.output_list, head) { struct intel_output *intel_output = output->driver_private; int crtc_mask = 0, clone_mask = 0; diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 62e21a5e..51c52c84 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -58,6 +58,7 @@ struct intel_crtc { int plane; uint32_t cursor_addr; u8 lut_r[256], lut_g[256], lut_b[256]; + int dpms_mode; }; struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, @@ -78,6 +79,11 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); extern void intel_wait_for_vblank(struct drm_device *dev); extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); +extern struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, + struct drm_display_mode *mode, + int *dpms_mode); +extern void intel_release_load_detect_pipe(struct drm_output *output, + int dpms_mode); extern struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB); extern int intel_sdvo_supports_hotplug(struct drm_output *output); |