From e239882b1e90cba0297118ec7dc432bea06b0bd0 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 4 Dec 2007 15:36:36 +0100 Subject: Modesetting Hotplug --- linux-core/drmP.h | 2 ++ linux-core/drm_bo.c | 1 - linux-core/drm_crtc.c | 54 +++++++++++++++++++++++++++++++++-- linux-core/drm_crtc.h | 1 + linux-core/drm_drv.c | 8 ++++-- linux-core/drm_mm.c | 15 ++++++++++ linux-core/i915_drv.c | 5 ++-- linux-core/intel_crt.c | 10 +++++++ linux-core/intel_drv.h | 5 ++++ linux-core/intel_fb.c | 45 +++++++++++++++++++++++++++-- linux-core/intel_sdvo.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++--- 11 files changed, 208 insertions(+), 14 deletions(-) (limited to 'linux-core') 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 @@ -1122,6 +1124,54 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, return 0; } +/** + * 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 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) { -- cgit v1.2.3