summaryrefslogtreecommitdiff
path: root/linux-core/intel_display.c
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@nietzche.virtuousgeek.org>2008-04-09 14:07:55 -0700
committerJesse Barnes <jbarnes@nietzche.virtuousgeek.org>2008-04-09 14:13:38 -0700
commit6c92689dcc627886c32afd4eca8f0da25bd07183 (patch)
treee70e5564b3fa12e975b5409764a89e5dfeebac6d /linux-core/intel_display.c
parent256a96135e6b48f5d3545896f7226edea8c70a0c (diff)
Port pipe reservation code for load detection
TV out needs to do load detection, which means we have to find an available pipe to use for the detection. Port over the pipe reservation code for this purpose.
Diffstat (limited to 'linux-core/intel_display.c')
-rw-r--r--linux-core/intel_display.c130
1 files changed, 128 insertions, 2 deletions
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;