Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 196501
b: refs/heads/master
c: eb1f8e4
h: refs/heads/master
i:
  196499: a178154
v: v3
  • Loading branch information
Dave Airlie committed May 18, 2010
1 parent 7fa9e14 commit 044913e
Show file tree
Hide file tree
Showing 27 changed files with 212 additions and 158 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0ddfa7d574e0f3a7510b0be6c8ed807af017223f
refs/heads/master: eb1f8e4f3be898df808e2dfc131099f5831d491d
2 changes: 1 addition & 1 deletion trunk/drivers/gpu/drm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ menuconfig DRM
depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU
select I2C
select I2C_ALGOBIT
select SLOW_WORK
help
Kernel-level support for the Direct Rendering Infrastructure (DRI)
introduced in XFree86 4.0. If you say Y here, you need to select
Expand All @@ -23,7 +24,6 @@ config DRM_KMS_HELPER
depends on DRM
select FB
select FRAMEBUFFER_CONSOLE if !EMBEDDED
select SLOW_WORK
help
FB and CRTC helpers for KMS drivers.

Expand Down
95 changes: 95 additions & 0 deletions trunk/drivers/gpu/drm/drm_crtc_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -807,3 +807,98 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
return 0;
}
EXPORT_SYMBOL(drm_helper_resume_force_mode);

static struct slow_work_ops output_poll_ops;

#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
static void output_poll_execute(struct slow_work *work)
{
struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work);
struct drm_connector *connector;
enum drm_connector_status old_status, status;
bool repoll = false, changed = false;
int ret;

mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {

/* if this is HPD or polled don't check it -
TV out for instance */
if (!connector->polled)
continue;

else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
repoll = true;

old_status = connector->status;
/* if we are connected and don't want to poll for disconnect
skip it */
if (old_status == connector_status_connected &&
!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) &&
!(connector->polled & DRM_CONNECTOR_POLL_HPD))
continue;

status = connector->funcs->detect(connector);
if (old_status != status)
changed = true;
}

mutex_unlock(&dev->mode_config.mutex);

if (changed) {
/* send a uevent + call fbdev */
drm_sysfs_hotplug_event(dev);
if (dev->mode_config.funcs->output_poll_changed)
dev->mode_config.funcs->output_poll_changed(dev);
}

if (repoll) {
ret = delayed_slow_work_enqueue(delayed_work, DRM_OUTPUT_POLL_PERIOD);
if (ret)
DRM_ERROR("delayed enqueue failed %d\n", ret);
}
}

void drm_kms_helper_poll_init(struct drm_device *dev)
{
struct drm_connector *connector;
bool poll = false;
int ret;

list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->polled)
poll = true;
}
slow_work_register_user(THIS_MODULE);
delayed_slow_work_init(&dev->mode_config.output_poll_slow_work,
&output_poll_ops);

if (poll) {
ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD);
if (ret)
DRM_ERROR("delayed enqueue failed %d\n", ret);
}
}
EXPORT_SYMBOL(drm_kms_helper_poll_init);

void drm_kms_helper_poll_fini(struct drm_device *dev)
{
delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
slow_work_unregister_user(THIS_MODULE);
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);

void drm_helper_hpd_irq_event(struct drm_device *dev)
{
if (!dev->mode_config.poll_enabled)
return;
delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
/* schedule a slow work asap */
delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0);
}
EXPORT_SYMBOL(drm_helper_hpd_irq_event);

static struct slow_work_ops output_poll_ops = {
.execute = output_poll_execute,
};
123 changes: 18 additions & 105 deletions trunk/drivers/gpu/drm/drm_fb_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ MODULE_LICENSE("GPL and additional rights");

static LIST_HEAD(kernel_fb_helper_list);

static struct slow_work_ops output_status_change_ops;

/* simple single crtc case helper function */
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
{
Expand Down Expand Up @@ -425,19 +423,13 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)

int drm_fb_helper_init(struct drm_device *dev,
struct drm_fb_helper *fb_helper,
int crtc_count, int max_conn_count,
bool polled)
int crtc_count, int max_conn_count)
{
struct drm_crtc *crtc;
int ret = 0;
int i;

fb_helper->dev = dev;
fb_helper->poll_enabled = polled;

slow_work_register_user(THIS_MODULE);
delayed_slow_work_init(&fb_helper->output_status_change_slow_work,
&output_status_change_ops);

INIT_LIST_HEAD(&fb_helper->kernel_fb_list);

Expand Down Expand Up @@ -494,8 +486,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)

drm_fb_helper_crtc_free(fb_helper);

delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
slow_work_unregister_user(THIS_MODULE);
}
EXPORT_SYMBOL(drm_fb_helper_fini);

Expand Down Expand Up @@ -713,7 +703,7 @@ int drm_fb_helper_set_par(struct fb_info *info)

if (fb_helper->delayed_hotplug) {
fb_helper->delayed_hotplug = false;
delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
drm_fb_helper_hotplug_event(fb_helper);
}
return 0;
}
Expand Down Expand Up @@ -826,7 +816,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
/* hmm everyone went away - assume VGA cable just fell out
and will come back later. */
DRM_ERROR("Cannot find any crtc or sizes - going 1024x768\n");
DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n");
sizes.fb_width = sizes.surface_width = 1024;
sizes.fb_height = sizes.surface_height = 768;
}
Expand Down Expand Up @@ -1292,123 +1282,46 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
* we shouldn't end up with no modes here.
*/
if (count == 0) {
if (fb_helper->poll_enabled) {
delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work,
5*HZ);
printk(KERN_INFO "No connectors reported connected with modes - started polling\n");
} else
printk(KERN_INFO "No connectors reported connected with modes\n");
printk(KERN_INFO "No connectors reported connected with modes\n");
}
drm_setup_crtcs(fb_helper);

return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
}
EXPORT_SYMBOL(drm_fb_helper_initial_config);

/* we got a hotplug irq - need to update fbcon */
void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper)
{
/* if we don't have the fbdev registered yet do nothing */
if (!fb_helper->fbdev)
return;

/* schedule a slow work asap */
delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
}
EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event);

bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled)
bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
{
int count = 0;
int ret;
u32 max_width, max_height, bpp_sel;

if (!fb_helper->fb)
return false;
DRM_DEBUG_KMS("\n");

max_width = fb_helper->fb->width;
max_height = fb_helper->fb->height;
bpp_sel = fb_helper->fb->bits_per_pixel;

count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
max_height);
if (fb_helper->poll_enabled && !polled) {
if (count) {
delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
} else {
ret = delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 5*HZ);
}
}
drm_setup_crtcs(fb_helper);

return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
}
EXPORT_SYMBOL(drm_helper_fb_hotplug_event);

/*
* delayed work queue execution function
* - check if fbdev is actually in use on the gpu
* - if not set delayed flag and repoll if necessary
* - check for connector status change
* - repoll if 0 modes found
*- call driver output status changed notifier
*/
static void output_status_change_execute(struct slow_work *work)
{
struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_status_change_slow_work);
struct drm_connector *connector;
enum drm_connector_status old_status, status;
bool repoll, changed = false;
int ret;
int i;
bool bound = false, crtcs_bound = false;
struct drm_crtc *crtc;

repoll = fb_helper->poll_enabled;
if (!fb_helper->fb)
return false;

/* first of all check the fbcon framebuffer is actually bound to any crtc */
/* take into account that no crtc at all maybe bound */
list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
if (crtc->fb)
crtcs_bound = true;
if (crtc->fb == fb_helper->fb)
bound = true;
}

if (bound == false && crtcs_bound) {
if (!bound && crtcs_bound) {
fb_helper->delayed_hotplug = true;
goto requeue;
return false;
}
DRM_DEBUG_KMS("\n");

for (i = 0; i < fb_helper->connector_count; i++) {
connector = fb_helper->connector_info[i]->connector;
old_status = connector->status;
status = connector->funcs->detect(connector);
if (old_status != status) {
changed = true;
}
if (status == connector_status_connected && repoll) {
DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector));
repoll = false;
}
}
max_width = fb_helper->fb->width;
max_height = fb_helper->fb->height;
bpp_sel = fb_helper->fb->bits_per_pixel;

if (changed) {
if (fb_helper->funcs->fb_output_status_changed)
fb_helper->funcs->fb_output_status_changed(fb_helper);
}
count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
max_height);
drm_setup_crtcs(fb_helper);

requeue:
if (repoll) {
ret = delayed_slow_work_enqueue(delayed_work, 5*HZ);
if (ret)
DRM_ERROR("delayed enqueue failed %d\n", ret);
}
return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
}

static struct slow_work_ops output_status_change_ops = {
.execute = output_status_change_execute,
};
EXPORT_SYMBOL(drm_fb_helper_hotplug_event);

2 changes: 1 addition & 1 deletion trunk/drivers/gpu/drm/i915/i915_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1493,7 +1493,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
I915_WRITE(INSTPM, (1 << 5) | (1 << 21));

intel_fbdev_init(dev);

drm_kms_helper_poll_init(dev);
return 0;

destroy_ringbuffer:
Expand Down
3 changes: 1 addition & 2 deletions trunk/drivers/gpu/drm/i915/i915_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
}
}
/* Just fire off a uevent and let userspace tell us what to do */
intelfb_hotplug(dev, false);
drm_sysfs_hotplug_event(dev);
drm_helper_hpd_irq_event(dev);
}

static void i915_handle_rps_change(struct drm_device *dev)
Expand Down
5 changes: 5 additions & 0 deletions trunk/drivers/gpu/drm/i915/intel_crt.c
Original file line number Diff line number Diff line change
Expand Up @@ -577,5 +577,10 @@ void intel_crt_init(struct drm_device *dev)

drm_sysfs_connector_add(connector);

if (I915_HAS_HOTPLUG(dev))
connector->polled = DRM_CONNECTOR_POLL_HPD;
else
connector->polled = DRM_CONNECTOR_POLL_CONNECT;

dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
}
2 changes: 2 additions & 0 deletions trunk/drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -4959,6 +4959,7 @@ intel_user_framebuffer_create(struct drm_device *dev,

static const struct drm_mode_config_funcs intel_mode_funcs = {
.fb_create = intel_user_framebuffer_create,
.output_poll_changed = intel_fb_output_poll_changed,
};

static struct drm_gem_object *
Expand Down Expand Up @@ -5346,6 +5347,7 @@ void intel_modeset_cleanup(struct drm_device *dev)

mutex_lock(&dev->struct_mutex);

drm_kms_helper_poll_fini(dev);
intel_fbdev_fini(dev);

list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/gpu/drm/i915/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
DRM_MODE_CONNECTOR_DisplayPort);
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);

connector->polled = DRM_CONNECTOR_POLL_HPD;

if (output_reg == DP_A)
intel_encoder->type = INTEL_OUTPUT_EDP;
else
Expand Down
2 changes: 1 addition & 1 deletion trunk/drivers/gpu/drm/i915/intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,5 +235,5 @@ extern int intel_overlay_put_image(struct drm_device *dev, void *data,
extern int intel_overlay_attrs(struct drm_device *dev, void *data,
struct drm_file *file_priv);

void intelfb_hotplug(struct drm_device *dev, bool polled);
extern void intel_fb_output_poll_changed(struct drm_device *dev);
#endif /* __INTEL_DRV_H__ */
Loading

0 comments on commit 044913e

Please sign in to comment.