29,22 → 29,27 |
* Jesse Barnes <jesse.barnes@intel.com> |
*/ |
|
#include "drmP.h" |
#include "drm_crtc.h" |
#include "drm_crtc_helper.h" |
#include "drm_fb_helper.h" |
#include <linux/export.h> |
#include <linux/moduleparam.h> |
|
#include <drm/drmP.h> |
#include <drm/drm_crtc.h> |
#include <drm/drm_fourcc.h> |
#include <drm/drm_crtc_helper.h> |
#include <drm/drm_fb_helper.h> |
#include <drm/drm_edid.h> |
|
static bool drm_kms_helper_poll = true; |
|
static void drm_mode_validate_flag(struct drm_connector *connector, |
int flags) |
{ |
struct drm_display_mode *mode, *t; |
struct drm_display_mode *mode; |
|
if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE)) |
return; |
|
list_for_each_entry_safe(mode, t, &connector->modes, head) { |
list_for_each_entry(mode, &connector->modes, head) { |
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && |
!(flags & DRM_MODE_FLAG_INTERLACE)) |
mode->status = MODE_NO_INTERLACE; |
82,7 → 87,7 |
uint32_t maxX, uint32_t maxY) |
{ |
struct drm_device *dev = connector->dev; |
struct drm_display_mode *mode, *t; |
struct drm_display_mode *mode; |
struct drm_connector_helper_funcs *connector_funcs = |
connector->helper_private; |
int count = 0; |
91,7 → 96,7 |
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, |
drm_get_connector_name(connector)); |
/* set all modes to the unverified state */ |
list_for_each_entry_safe(mode, t, &connector->modes, head) |
list_for_each_entry(mode, &connector->modes, head) |
mode->status = MODE_UNVERIFIED; |
|
if (connector->force) { |
113,7 → 118,12 |
goto prune; |
} |
|
#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE |
count = drm_load_edid_firmware(connector); |
if (count == 0) |
#endif |
count = (*connector_funcs->get_modes)(connector); |
|
if (count == 0 && connector->status == connector_status_connected) |
count = drm_add_modes_noedid(connector, 1024, 768); |
if (count == 0) |
131,7 → 141,7 |
mode_flags |= DRM_MODE_FLAG_DBLSCAN; |
drm_mode_validate_flag(connector, mode_flags); |
|
list_for_each_entry_safe(mode, t, &connector->modes, head) { |
list_for_each_entry(mode, &connector->modes, head) { |
if (mode->status == MODE_OK) |
mode->status = connector_funcs->mode_valid(connector, |
mode); |
147,7 → 157,7 |
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, |
drm_get_connector_name(connector)); |
list_for_each_entry_safe(mode, t, &connector->modes, head) { |
list_for_each_entry(mode, &connector->modes, head) { |
mode->vrefresh = drm_mode_vrefresh(mode); |
|
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
258,6 → 268,7 |
crtc->fb = NULL; |
} |
} |
|
} |
EXPORT_SYMBOL(drm_helper_disable_unused_functions); |
|
342,12 → 353,20 |
struct drm_encoder *encoder; |
bool ret = true; |
|
ENTER(); |
|
crtc->enabled = drm_helper_crtc_in_use(crtc); |
if (!crtc->enabled) |
return true; |
|
printf("crtc->enabled\n"); |
|
adjusted_mode = drm_mode_duplicate(dev, mode); |
if (!adjusted_mode) |
return false; |
|
printf("adjusted_mode\n"); |
|
saved_hwmode = crtc->hwmode; |
saved_mode = crtc->mode; |
saved_x = crtc->x; |
371,11 → 390,16 |
encoder_funcs = encoder->helper_private; |
if (!(ret = encoder_funcs->mode_fixup(encoder, mode, |
adjusted_mode))) { |
DRM_DEBUG_KMS("Encoder fixup failed\n"); |
goto done; |
} |
} |
|
printf("list_for_each_entry\n"); |
printf("mode_fixup %x\n", crtc_funcs->mode_fixup); |
|
if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { |
DRM_DEBUG_KMS("CRTC fixup failed\n"); |
goto done; |
} |
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); |
445,11 → 469,37 |
crtc->y = saved_y; |
} |
|
LEAVE(); |
|
return ret; |
} |
EXPORT_SYMBOL(drm_crtc_helper_set_mode); |
|
|
static int |
drm_crtc_helper_disable(struct drm_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_connector *connector; |
struct drm_encoder *encoder; |
|
/* Decouple all encoders and their attached connectors from this crtc */ |
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
if (encoder->crtc != crtc) |
continue; |
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
if (connector->encoder != encoder) |
continue; |
|
connector->encoder = NULL; |
} |
} |
|
drm_helper_disable_unused_functions(dev); |
return 0; |
} |
|
/** |
* drm_crtc_helper_set_config - set a new config from userspace |
* @crtc: CRTC to setup |
478,7 → 528,8 |
struct drm_connector *save_connectors, *connector; |
int count = 0, ro, fail = 0; |
struct drm_crtc_helper_funcs *crtc_funcs; |
int ret = 0; |
struct drm_mode_set save_set; |
int ret; |
int i; |
|
DRM_DEBUG_KMS("\n"); |
503,8 → 554,7 |
(int)set->num_connectors, set->x, set->y); |
} else { |
DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); |
set->mode = NULL; |
set->num_connectors = 0; |
return drm_crtc_helper_disable(set->crtc); |
} |
|
dev = set->crtc->dev; |
550,6 → 600,12 |
save_connectors[count++] = *connector; |
} |
|
save_set.crtc = set->crtc; |
save_set.mode = &set->crtc->mode; |
save_set.x = set->crtc->x; |
save_set.y = set->crtc->y; |
save_set.fb = set->crtc->fb; |
|
/* We should be able to check here if the fb has the same properties |
* and then just flip_or_move it */ |
if (set->crtc->fb != set->fb) { |
674,7 → 730,7 |
for (i = 0; i < set->num_connectors; i++) { |
DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, |
drm_get_connector_name(set->connectors[i])); |
set->connectors[i]->dpms = DRM_MODE_DPMS_ON; |
set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); |
} |
} |
drm_helper_disable_unused_functions(dev); |
715,6 → 771,12 |
*connector = save_connectors[count++]; |
} |
|
/* Try to restore the config */ |
if (mode_changed && |
!drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x, |
save_set.y, save_set.fb)) |
DRM_ERROR("failed to restore config after modeset failure\n"); |
|
kfree(save_connectors); |
kfree(save_encoders); |
kfree(save_crtcs); |
805,13 → 867,19 |
EXPORT_SYMBOL(drm_helper_connector_dpms); |
|
int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, |
struct drm_mode_fb_cmd *mode_cmd) |
struct drm_mode_fb_cmd2 *mode_cmd) |
{ |
int i; |
|
fb->width = mode_cmd->width; |
fb->height = mode_cmd->height; |
fb->pitch = mode_cmd->pitch; |
fb->bits_per_pixel = mode_cmd->bpp; |
fb->depth = mode_cmd->depth; |
for (i = 0; i < 4; i++) { |
fb->pitches[i] = mode_cmd->pitches[i]; |
fb->offsets[i] = mode_cmd->offsets[i]; |
} |
drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, |
&fb->bits_per_pixel); |
fb->pixel_format = mode_cmd->pixel_format; |
|
return 0; |
} |
913,7 → 981,7 |
} |
|
if (repoll) |
queue_delayed_work(system_nrt_wq, delayed_work, DRM_OUTPUT_POLL_PERIOD); |
schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); |
} |
|
void drm_kms_helper_poll_disable(struct drm_device *dev) |
938,7 → 1006,7 |
} |
|
if (poll) |
queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); |
schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); |
} |
EXPORT_SYMBOL(drm_kms_helper_poll_enable); |
|
965,9 → 1033,8 |
/* kill timer and schedule immediate execution, this doesn't block */ |
cancel_delayed_work(&dev->mode_config.output_poll_work); |
if (drm_kms_helper_poll) |
queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0); |
schedule_delayed_work(&dev->mode_config.output_poll_work, 0); |
} |
EXPORT_SYMBOL(drm_helper_hpd_irq_event); |
|
|
#endif |