summaryrefslogtreecommitdiff
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
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.
-rw-r--r--linux-core/drm_crtc.h1
-rw-r--r--linux-core/intel_display.c130
-rw-r--r--linux-core/intel_drv.h6
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);