summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
authorJakob Bornecrantz <jakob@tungstengraphics.com>2007-12-04 15:36:36 +0100
committerJakob Bornecrantz <jakob@aurora.(none)>2007-12-18 02:21:08 +0100
commite239882b1e90cba0297118ec7dc432bea06b0bd0 (patch)
tree79516ad9a1e9ba8f5447ca9532fb3576cf6ac5ec /linux-core
parentf62a300547b1f495472f773587cd20c6c9da06aa (diff)
Modesetting Hotplug
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drmP.h2
-rw-r--r--linux-core/drm_bo.c1
-rw-r--r--linux-core/drm_crtc.c54
-rw-r--r--linux-core/drm_crtc.h1
-rw-r--r--linux-core/drm_drv.c8
-rw-r--r--linux-core/drm_mm.c15
-rw-r--r--linux-core/i915_drv.c5
-rw-r--r--linux-core/intel_crt.c10
-rw-r--r--linux-core/intel_drv.h5
-rw-r--r--linux-core/intel_fb.c45
-rw-r--r--linux-core/intel_sdvo.c76
11 files changed, 208 insertions, 14 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 4a0cabc3..5e674b2a 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -669,6 +669,7 @@ struct drm_driver {
/* FB routines, if present */
int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc);
int (*fb_remove)(struct drm_device *dev, struct drm_crtc *crtc);
+ int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc);
struct drm_fence_driver *fence_driver;
struct drm_bo_driver *bo_driver;
@@ -1210,6 +1211,7 @@ extern int drm_mm_clean(struct drm_mm *mm);
extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size);
extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size);
+extern void drm_mm_print(struct drm_mm *mm, const char *name);
static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
{
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index 7a123dad..068ccf00 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -569,7 +569,6 @@ void drm_putback_buffer_objects(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_putback_buffer_objects);
-
/*
* Note. The caller has to register (if applicable)
* and deregister fence object usage.
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index e1b37c0b..ac2f1d42 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -382,6 +382,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY)
drm_crtc_probe_single_output_modes(output, maxX, maxY);
}
}
+EXPORT_SYMBOL(drm_crtc_probe_output_modes);
/**
* drm_crtc_set_mode - set a mode
@@ -539,7 +540,8 @@ void drm_disable_unused_functions(struct drm_device *dev)
crtc->funcs->dpms(crtc, DPMSModeOff);
}
}
-
+EXPORT_SYMBOL(drm_disable_unused_functions);
+
/**
* drm_mode_probed_add - add a mode to the specified output's probed mode list
* @output: output the new mode
@@ -936,7 +938,7 @@ clone:
}
}
}
-
+EXPORT_SYMBOL(drm_pick_crtcs);
/**
* drm_initial_config - setup a sane initial output configuration
@@ -1123,6 +1125,54 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info,
}
/**
+ * drm_hotplug_stage_two
+ * @dev DRM device
+ * @output hotpluged output
+ *
+ * LOCKING.
+ * Caller must hold mode config lock, function might grap struct lock.
+ *
+ * Stage two of a hotplug.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output)
+{
+ int has_config = 0;
+
+ if (output->crtc && output->crtc->desired_mode) {
+ DRM_DEBUG("drm thinks that output already has a config\n");
+ has_config = 1;
+ }
+
+ drm_crtc_probe_output_modes(dev, 2048, 2048);
+
+ if (!has_config)
+ drm_pick_crtcs(dev);
+
+ if (!output->crtc || !output->crtc->desired_mode) {
+ DRM_DEBUG("could not find a desired mode or crtc for output\n");
+ return 1;
+ }
+
+ /* We should realy check if there is a fb using this crtc */
+ if (!has_config)
+ dev->driver->fb_probe(dev, output->crtc);
+ else {
+ dev->driver->fb_resize(dev, output->crtc);
+
+ if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0))
+ DRM_ERROR("failed to set mode after hotplug\n");
+ }
+
+ drm_disable_unused_functions(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_hotplug_stage_two);
+
+/**
* drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
* @out: drm_mode_modeinfo struct to return to the user
* @in: drm_display_mode to use
diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h
index 6b6e1dbf..ce502062 100644
--- a/linux-core/drm_crtc.h
+++ b/linux-core/drm_crtc.h
@@ -577,6 +577,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 int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output);
extern int drm_output_attach_property(struct drm_output *output,
struct drm_property *property, uint64_t init_val);
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index 0b9ce30a..ab02c659 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -181,6 +181,7 @@ int drm_lastclose(struct drm_device * dev)
DRM_DEBUG("\n");
+/* return 0; */
/*
* We can't do much about this function failing.
*/
@@ -195,8 +196,8 @@ int drm_lastclose(struct drm_device * dev)
dev->unique_len = 0;
}
- if (dev->irq_enabled)
- drm_irq_uninstall(dev);
+/* if (dev->irq_enabled)
+ drm_irq_uninstall(dev); */
/* Free drawable information memory */
mutex_lock(&dev->struct_mutex);
@@ -251,12 +252,13 @@ int drm_lastclose(struct drm_device * dev)
drm_ctl_free(vma, sizeof(*vma), DRM_MEM_VMAS);
}
+ /*
list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
if (!(r_list->map->flags & _DRM_DRIVER)) {
drm_rmmap_locked(dev, r_list->map);
r_list = NULL;
}
- }
+ }*/
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) {
for (i = 0; i < dev->queue_count; i++) {
diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c
index 59110293..28726a65 100644
--- a/linux-core/drm_mm.c
+++ b/linux-core/drm_mm.c
@@ -294,3 +294,18 @@ void drm_mm_takedown(struct drm_mm * mm)
}
EXPORT_SYMBOL(drm_mm_takedown);
+
+void drm_mm_print(struct drm_mm *mm, const char *name)
+{
+ struct list_head *list;
+ const struct list_head *mm_stack = &mm->ml_entry;
+ struct drm_mm_node *entry;
+
+ DRM_DEBUG("Memory usage for '%s'\n", name ? name : "unknown");
+ list_for_each(list, mm_stack) {
+ entry = list_entry(list, struct drm_mm_node, ml_entry);
+ DRM_DEBUG("\t0x%08lx %li %s pages\n", entry->start, entry->size,
+ entry->free ? "free" : "used");
+ }
+}
+EXPORT_SYMBOL(drm_mm_print);
diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c
index fb4149c4..598039dc 100644
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@ -541,8 +541,8 @@ static struct drm_driver driver = {
DRIVER_IRQ_VBL2,
.load = i915_driver_load,
.unload = i915_driver_unload,
- .lastclose = i915_driver_lastclose,
- .preclose = i915_driver_preclose,
+/* .lastclose = i915_driver_lastclose,
+ .preclose = i915_driver_preclose, */
.suspend = i915_suspend,
.resume = i915_resume,
.device_is_agp = i915_driver_device_is_agp,
@@ -557,6 +557,7 @@ static struct drm_driver driver = {
.get_reg_ofs = drm_core_get_reg_ofs,
.fb_probe = intelfb_probe,
.fb_remove = intelfb_remove,
+ .fb_resize = intelfb_resize,
.ioctls = i915_ioctls,
.fops = {
.owner = THIS_MODULE,
diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c
index 722a62c8..864b1a25 100644
--- a/linux-core/intel_crt.c
+++ b/linux-core/intel_crt.c
@@ -142,6 +142,7 @@ static bool intel_crt_detect_hotplug(struct drm_output *output)
struct drm_device *dev = output->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 temp;
+#if 1
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
temp = I915_READ(PORT_HOTPLUG_EN);
@@ -160,6 +161,15 @@ static bool intel_crt_detect_hotplug(struct drm_output *output)
return true;
return false;
+#else
+ temp = I915_READ(PORT_HOTPLUG_STAT);
+ DRM_DEBUG("HST 0x%08x\n", temp);
+
+ if (temp & (1 << 8) && temp & (1 << 9))
+ return true;
+
+ return false;
+#endif
}
static bool intel_crt_detect_ddc(struct drm_output *output)
diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h
index 7de4b924..06335b18 100644
--- a/linux-core/intel_drv.h
+++ b/linux-core/intel_drv.h
@@ -76,7 +76,12 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
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_output* intel_sdvo_find(struct drm_device *dev, int sdvoB);
+extern int intel_sdvo_supports_hotplug(struct drm_output *output);
+extern void intel_sdvo_set_hotplug(struct drm_output *output, int enable);
+
extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
extern int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc);
+extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc);
#endif /* __INTEL_DRV_H__ */
diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c
index 32c7dc31..b67c0fcc 100644
--- a/linux-core/intel_fb.c
+++ b/linux-core/intel_fb.c
@@ -489,6 +489,46 @@ static struct fb_ops intelfb_ops = {
.fb_imageblit = cfb_imageblit, //intelfb_imageblit,
};
+/**
+ * Curretly it is assumed that the old framebuffer is reused.
+ *
+ * LOCKING
+ * caller should hold the mode config lock.
+ *
+ */
+int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
+{
+ struct fb_info *info;
+ struct drm_framebuffer *fb;
+ struct drm_display_mode *mode = crtc->desired_mode;
+
+ fb = crtc->fb;
+ if (!fb)
+ return 1;
+
+ info = fb->fbdev;
+ if (!info)
+ return 1;
+
+ if (!mode)
+ return 1;
+
+ info->var.xres = mode->hdisplay;
+ info->var.right_margin = mode->hsync_start - mode->hdisplay;
+ info->var.hsync_len = mode->hsync_end - mode->hsync_start;
+ info->var.left_margin = mode->htotal - mode->hsync_end;
+ info->var.yres = mode->vdisplay;
+ info->var.lower_margin = mode->vsync_start - mode->vdisplay;
+ info->var.vsync_len = mode->vsync_end - mode->vsync_start;
+ info->var.upper_margin = mode->vtotal - mode->vsync_end;
+ info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
+ /* avoid overflow */
+ info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
+
+ return 0;
+}
+EXPORT_SYMBOL(intelfb_resize);
+
int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
{
struct fb_info *info;
@@ -512,8 +552,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
}
crtc->fb = fb;
- fb->width = crtc->desired_mode->hdisplay;
- fb->height = crtc->desired_mode->vdisplay;
+ /* To allow resizeing without swapping buffers */
+ fb->width = 2048;/* crtc->desired_mode->hdisplay; */
+ fb->height = 2048;/* crtc->desired_mode->vdisplay; */
fb->bits_per_pixel = 32;
fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8);
diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c
index 0da57faa..d2d00e2a 100644
--- a/linux-core/intel_sdvo.c
+++ b/linux-core/intel_sdvo.c
@@ -60,7 +60,7 @@ struct intel_sdvo_priv {
* SDVOB and SDVOC to work around apparent hardware issues (according to
* comments in the BIOS).
*/
-static void intel_sdvo_write_sdvox(struct drm_output *output, u32 val)
+void intel_sdvo_write_sdvox(struct drm_output *output, u32 val)
{
struct drm_device *dev = output->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -69,10 +69,12 @@ static void intel_sdvo_write_sdvox(struct drm_output *output, u32 val)
u32 bval = val, cval = val;
int i;
- if (sdvo_priv->output_device == SDVOB)
+ if (sdvo_priv->output_device == SDVOB) {
cval = I915_READ(SDVOC);
- else
- bval = I915_READ(SDVOB);
+ bval = bval | (1 << 26);
+ } else {
+ bval = I915_READ(SDVOB) | (1 << 26);
+ }
/*
* Write the registers twice for luck. Sometimes,
* writing them only once doesn't appear to 'stick'.
@@ -879,6 +881,72 @@ void intel_sdvo_dump(void)
}
+struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB)
+{
+ struct drm_output *output = 0;
+ struct intel_output *iout = 0;
+ struct intel_sdvo_priv *sdvo;
+
+ /* find the sdvo output */
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+ iout = output->driver_private;
+
+ if (iout->type != INTEL_OUTPUT_SDVO)
+ continue;
+
+ sdvo = iout->dev_priv;
+
+ if (sdvo->output_device == SDVOB && sdvoB)
+ return output;
+
+ if (sdvo->output_device == SDVOC && !sdvoB)
+ return output;
+
+ }
+
+ return 0;
+}
+
+int intel_sdvo_supports_hotplug(struct drm_output *output)
+{
+ u8 response[2];
+ u8 status;
+ DRM_DEBUG("\n");
+
+ if (!output)
+ return 0;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
+ status = intel_sdvo_read_response(output, &response, 2);
+
+ if (response[0] !=0)
+ return 1;
+
+ return 0;
+}
+
+void intel_sdvo_set_hotplug(struct drm_output *output, int on)
+{
+ u8 response[2];
+ u8 status;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
+ intel_sdvo_read_response(output, &response, 2);
+
+ if (on) {
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
+ status = intel_sdvo_read_response(output, &response, 2);
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
+ } else {
+ response[0] = 0;
+ response[1] = 0;
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
+ }
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
+ intel_sdvo_read_response(output, &response, 2);
+}
static enum drm_output_status intel_sdvo_detect(struct drm_output *output)
{