39,6 → 39,10 |
#include <drm/drm_fb_helper.h> |
#include <drm/drm_edid.h> |
|
MODULE_AUTHOR("David Airlie, Jesse Barnes"); |
MODULE_DESCRIPTION("DRM KMS helper"); |
MODULE_LICENSE("GPL and additional rights"); |
|
/** |
* drm_helper_move_panel_connectors_to_head() - move panels to the front in the |
* connector list |
76,7 → 80,8 |
{ |
struct drm_display_mode *mode; |
|
if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE)) |
if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE | |
DRM_MODE_FLAG_3D_MASK)) |
return; |
|
list_for_each_entry(mode, &connector->modes, head) { |
86,6 → 91,9 |
if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && |
!(flags & DRM_MODE_FLAG_DBLSCAN)) |
mode->status = MODE_NO_DBLESCAN; |
if ((mode->flags & DRM_MODE_FLAG_3D_MASK) && |
!(flags & DRM_MODE_FLAG_3D_MASK)) |
mode->status = MODE_NO_STEREO; |
} |
|
return; |
105,9 → 113,9 |
* then culled (based on validity and the @maxX, @maxY parameters) and put into |
* the normal modes list. |
* |
* Intended to be use as a generic implementation of the ->probe() @connector |
* callback for drivers that use the crtc helpers for output mode filtering and |
* detection. |
* Intended to be use as a generic implementation of the ->fill_modes() |
* @connector vfunc for drivers that use the crtc helpers for output mode |
* filtering and detection. |
* |
* RETURNS: |
* Number of modes found on @connector. |
175,6 → 183,8 |
mode_flags |= DRM_MODE_FLAG_INTERLACE; |
if (connector->doublescan_allowed) |
mode_flags |= DRM_MODE_FLAG_DBLSCAN; |
if (connector->stereo_allowed) |
mode_flags |= DRM_MODE_FLAG_3D_MASK; |
drm_mode_validate_flag(connector, mode_flags); |
|
list_for_each_entry(mode, &connector->modes, head) { |
314,35 → 324,6 |
} |
EXPORT_SYMBOL(drm_helper_disable_unused_functions); |
|
/** |
* drm_encoder_crtc_ok - can a given crtc drive a given encoder? |
* @encoder: encoder to test |
* @crtc: crtc to test |
* |
* Return false if @encoder can't be driven by @crtc, true otherwise. |
*/ |
static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, |
struct drm_crtc *crtc) |
{ |
struct drm_device *dev; |
struct drm_crtc *tmp; |
int crtc_mask = 1; |
|
WARN(!crtc, "checking null crtc?\n"); |
|
dev = crtc->dev; |
|
list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { |
if (tmp == crtc) |
break; |
crtc_mask <<= 1; |
} |
|
if (encoder->possible_crtcs & crtc_mask) |
return true; |
return false; |
} |
|
/* |
* Check the CRTC we're going to map each output to vs. its current |
* CRTC. If they don't match, we have to disable the output and the CRTC |
395,22 → 376,25 |
struct drm_framebuffer *old_fb) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; |
struct drm_display_mode *adjusted_mode, saved_mode; |
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
struct drm_encoder_helper_funcs *encoder_funcs; |
int saved_x, saved_y; |
bool saved_enabled; |
struct drm_encoder *encoder; |
bool ret = true; |
|
saved_enabled = crtc->enabled; |
crtc->enabled = drm_helper_crtc_in_use(crtc); |
if (!crtc->enabled) |
return true; |
|
adjusted_mode = drm_mode_duplicate(dev, mode); |
if (!adjusted_mode) |
if (!adjusted_mode) { |
crtc->enabled = saved_enabled; |
return false; |
} |
|
saved_hwmode = crtc->hwmode; |
saved_mode = crtc->mode; |
saved_x = crtc->x; |
saved_y = crtc->y; |
523,13 → 507,13 |
* are later needed by vblank and swap-completion |
* timestamping. They are derived from true hwmode. |
*/ |
drm_calc_timestamping_constants(crtc); |
drm_calc_timestamping_constants(crtc, &crtc->hwmode); |
|
/* FIXME: add subpixel order */ |
done: |
drm_mode_destroy(dev, adjusted_mode); |
if (!ret) { |
crtc->hwmode = saved_hwmode; |
crtc->enabled = saved_enabled; |
crtc->mode = saved_mode; |
crtc->x = saved_x; |
crtc->y = saved_y; |
557,6 → 541,14 |
continue; |
|
connector->encoder = NULL; |
|
/* |
* drm_helper_disable_unused_functions() ought to be |
* doing this, but since we've decoupled the encoder |
* from the connector above, the required connection |
* between them is henceforth no longer available. |
*/ |
connector->dpms = DRM_MODE_DPMS_OFF; |
} |
} |
|
583,9 → 575,8 |
int drm_crtc_helper_set_config(struct drm_mode_set *set) |
{ |
struct drm_device *dev; |
struct drm_crtc *save_crtcs, *new_crtc, *crtc; |
struct drm_crtc *new_crtc; |
struct drm_encoder *save_encoders, *new_encoder, *encoder; |
struct drm_framebuffer *old_fb = NULL; |
bool mode_changed = false; /* if true do a full mode set */ |
bool fb_changed = false; /* if true and !mode_changed just do a flip */ |
struct drm_connector *save_connectors, *connector; |
621,38 → 612,28 |
|
dev = set->crtc->dev; |
|
/* Allocate space for the backup of all (non-pointer) crtc, encoder and |
* connector data. */ |
save_crtcs = kzalloc(dev->mode_config.num_crtc * |
sizeof(struct drm_crtc), GFP_KERNEL); |
if (!save_crtcs) |
return -ENOMEM; |
|
/* |
* Allocate space for the backup of all (non-pointer) encoder and |
* connector data. |
*/ |
save_encoders = kzalloc(dev->mode_config.num_encoder * |
sizeof(struct drm_encoder), GFP_KERNEL); |
if (!save_encoders) { |
kfree(save_crtcs); |
if (!save_encoders) |
return -ENOMEM; |
} |
|
save_connectors = kzalloc(dev->mode_config.num_connector * |
sizeof(struct drm_connector), GFP_KERNEL); |
if (!save_connectors) { |
kfree(save_crtcs); |
kfree(save_encoders); |
return -ENOMEM; |
} |
|
/* Copy data. Note that driver private data is not affected. |
/* |
* Copy data. Note that driver private data is not affected. |
* Should anything bad happen only the expected state is |
* restored, not the drivers personal bookkeeping. |
*/ |
count = 0; |
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
save_crtcs[count++] = *crtc; |
} |
|
count = 0; |
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
save_encoders[count++] = *encoder; |
} |
775,19 → 756,17 |
mode_changed = true; |
|
if (mode_changed) { |
set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); |
if (set->crtc->enabled) { |
if (drm_helper_crtc_in_use(set->crtc)) { |
DRM_DEBUG_KMS("attempting to set mode from" |
" userspace\n"); |
drm_mode_debug_printmodeline(set->mode); |
old_fb = set->crtc->fb; |
set->crtc->fb = set->fb; |
if (!drm_crtc_helper_set_mode(set->crtc, set->mode, |
set->x, set->y, |
old_fb)) { |
save_set.fb)) { |
DRM_ERROR("failed to set mode on [CRTC:%d]\n", |
set->crtc->base.id); |
set->crtc->fb = old_fb; |
set->crtc->fb = save_set.fb; |
ret = -EINVAL; |
goto fail; |
} |
802,14 → 781,13 |
} else if (fb_changed) { |
set->crtc->x = set->x; |
set->crtc->y = set->y; |
|
old_fb = set->crtc->fb; |
if (set->crtc->fb != set->fb) |
set->crtc->fb = set->fb; |
ret = crtc_funcs->mode_set_base(set->crtc, |
set->x, set->y, old_fb); |
set->x, set->y, save_set.fb); |
if (ret != 0) { |
set->crtc->fb = old_fb; |
set->crtc->x = save_set.x; |
set->crtc->y = save_set.y; |
set->crtc->fb = save_set.fb; |
goto fail; |
} |
} |
816,17 → 794,11 |
|
kfree(save_connectors); |
kfree(save_encoders); |
kfree(save_crtcs); |
return 0; |
|
fail: |
/* Restore all previous data. */ |
count = 0; |
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
*crtc = save_crtcs[count++]; |
} |
|
count = 0; |
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
*encoder = save_encoders[count++]; |
} |
844,7 → 816,6 |
|
kfree(save_connectors); |
kfree(save_encoders); |
kfree(save_crtcs); |
return ret; |
} |
EXPORT_SYMBOL(drm_crtc_helper_set_config); |
1124,7 → 1095,7 |
} |
EXPORT_SYMBOL(drm_kms_helper_poll_fini); |
|
void drm_helper_hpd_irq_event(struct drm_device *dev) |
bool drm_helper_hpd_irq_event(struct drm_device *dev) |
{ |
struct drm_connector *connector; |
enum drm_connector_status old_status; |
1131,7 → 1102,7 |
bool changed = false; |
|
if (!dev->mode_config.poll_enabled) |
return; |
return false; |
|
mutex_lock(&dev->mode_config.mutex); |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
1156,5 → 1127,7 |
|
if (changed) |
drm_kms_helper_hotplug_event(dev); |
|
return changed; |
} |
EXPORT_SYMBOL(drm_helper_hpd_irq_event); |