33,15 → 33,6 |
#include "drm_crtc.h" |
#include "drm_crtc_helper.h" |
|
/* |
* Detailed mode info for 800x600@60Hz |
*/ |
static struct drm_display_mode std_modes[] = { |
{ DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840, |
968, 1056, 0, 600, 601, 605, 628, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
}; |
|
static void drm_mode_validate_flag(struct drm_connector *connector, |
int flags) |
{ |
94,7 → 85,7 |
int count = 0; |
int mode_flags = 0; |
|
DRM_DEBUG("%s\n", drm_get_connector_name(connector)); |
DRM_DEBUG_KMS("%s\n", drm_get_connector_name(connector)); |
/* set all modes to the unverified state */ |
list_for_each_entry_safe(mode, t, &connector->modes, head) |
mode->status = MODE_UNVERIFIED; |
102,15 → 93,17 |
connector->status = connector->funcs->detect(connector); |
|
if (connector->status == connector_status_disconnected) { |
DRM_DEBUG("%s is disconnected\n", |
DRM_DEBUG_KMS("%s is disconnected\n", |
drm_get_connector_name(connector)); |
/* TODO set EDID to NULL */ |
return 0; |
goto prune; |
} |
|
count = (*connector_funcs->get_modes)(connector); |
if (!count) { |
count = drm_add_modes_noedid(connector, 800, 600); |
if (!count) |
return 0; |
} |
|
drm_mode_connector_list_update(connector); |
|
130,7 → 123,7 |
mode); |
} |
|
|
prune: |
drm_mode_prune_invalid(dev, &connector->modes, true); |
|
if (list_empty(&connector->modes)) |
138,7 → 131,8 |
|
drm_mode_sort(&connector->modes); |
|
DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(connector)); |
DRM_DEBUG_KMS("Probed modes for %s\n", |
drm_get_connector_name(connector)); |
list_for_each_entry_safe(mode, t, &connector->modes, head) { |
mode->vrefresh = drm_mode_vrefresh(mode); |
|
165,39 → 159,6 |
} |
EXPORT_SYMBOL(drm_helper_probe_connector_modes); |
|
static void drm_helper_add_std_modes(struct drm_device *dev, |
struct drm_connector *connector) |
{ |
struct drm_display_mode *mode, *t; |
int i; |
|
for (i = 0; i < ARRAY_SIZE(std_modes); i++) { |
struct drm_display_mode *stdmode; |
|
/* |
* When no valid EDID modes are available we end up |
* here and bailed in the past, now we add some standard |
* modes and move on. |
*/ |
stdmode = drm_mode_duplicate(dev, &std_modes[i]); |
drm_mode_probed_add(connector, stdmode); |
drm_mode_list_concat(&connector->probed_modes, |
&connector->modes); |
|
DRM_DEBUG("Adding mode %s to %s\n", stdmode->name, |
drm_get_connector_name(connector)); |
} |
drm_mode_sort(&connector->modes); |
|
DRM_DEBUG("Added std modes on %s\n", drm_get_connector_name(connector)); |
list_for_each_entry_safe(mode, t, &connector->modes, head) { |
mode->vrefresh = drm_mode_vrefresh(mode); |
|
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
drm_mode_debug_printmodeline(mode); |
} |
} |
|
/** |
* drm_helper_encoder_in_use - check if a given encoder is in use |
* @encoder: encoder to check |
258,14 → 219,28 |
void drm_helper_disable_unused_functions(struct drm_device *dev) |
{ |
struct drm_encoder *encoder; |
struct drm_connector *connector; |
struct drm_encoder_helper_funcs *encoder_funcs; |
struct drm_crtc *crtc; |
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
if (!connector->encoder) |
continue; |
if (connector->status == connector_status_disconnected) |
connector->encoder = NULL; |
} |
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
encoder_funcs = encoder->helper_private; |
if (!drm_helper_encoder_in_use(encoder)) |
if (!drm_helper_encoder_in_use(encoder)) { |
if (encoder_funcs->disable) |
(*encoder_funcs->disable)(encoder); |
else |
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
/* disconnector encoder from any connector */ |
encoder->crtc = NULL; |
} |
} |
|
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
282,8 → 257,6 |
{ |
struct drm_display_mode *mode; |
|
ENTRY(); |
|
list_for_each_entry(mode, &connector->modes, head) { |
if (drm_mode_width(mode) > width || |
drm_mode_height(mode) > height) |
314,7 → 287,7 |
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
enabled[i] = drm_connector_enabled(connector, true); |
DRM_DEBUG("connector %d enabled ? %s\n", connector->base.id, |
DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, |
enabled[i] ? "yes" : "no"); |
any_enabled |= enabled[i]; |
i++; |
344,7 → 317,7 |
continue; |
} |
|
DRM_DEBUG("looking for preferred mode on connector %d\n", |
DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", |
connector->base.id); |
|
modes[i] = drm_has_preferred_mode(connector, width, height); |
353,7 → 326,7 |
list_for_each_entry(modes[i], &connector->modes, head) |
break; |
} |
DRM_DEBUG("found mode %s\n", modes[i] ? modes[i]->name : |
DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : |
"none"); |
i++; |
} |
382,8 → 355,6 |
c++; |
} |
|
dbgprintf("n= %d\n", n); |
|
best_crtcs[n] = NULL; |
best_crtc = NULL; |
best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); |
395,8 → 366,6 |
if (!crtcs) |
return best_score; |
|
dbgprintf("crtcs = %x\n", crtcs); |
|
my_score = 1; |
if (connector->status == connector_status_connected) |
my_score++; |
405,9 → 374,6 |
|
connector_funcs = connector->helper_private; |
encoder = connector_funcs->best_encoder(connector); |
|
dbgprintf("encoder = %x\n", encoder); |
|
if (!encoder) |
goto out; |
|
418,7 → 384,7 |
c = 0; |
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
|
if ((connector->encoder->possible_crtcs & (1 << c)) == 0) { |
if ((encoder->possible_crtcs & (1 << c)) == 0) { |
c++; |
continue; |
} |
448,11 → 414,6 |
} |
out: |
kfree(crtcs); |
|
dbgprintf("best_score= %x\n", best_score); |
|
LEAVE(); |
|
return best_score; |
} |
|
466,7 → 427,7 |
int width, height; |
int i, ret; |
|
DRM_DEBUG("\n"); |
DRM_DEBUG_KMS("\n"); |
|
width = 1280; //dev->mode_config.max_width; |
height = 1024; //dev->mode_config.max_height; |
489,7 → 450,7 |
if (!ret) |
DRM_ERROR("Unable to find initial modes\n"); |
|
DRM_DEBUG("picking CRTCs for %dx%d config\n", width, height); |
DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); |
|
drm_pick_crtcs(dev, crtcs, modes, 0, width, height); |
|
504,14 → 465,15 |
} |
|
if (mode && crtc) { |
DRM_DEBUG("desired mode %s set on crtc %d\n", |
DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", |
mode->name, crtc->base.id); |
crtc->desired_mode = mode; |
// crtc->mode = *mode; |
crtc->enabled = true; |
connector->encoder->crtc = crtc; |
} else |
} else { |
connector->encoder->crtc = NULL; |
connector->encoder = NULL; |
} |
i++; |
} |
|
518,8 → 480,6 |
kfree(crtcs); |
kfree(modes); |
kfree(enabled); |
|
LEAVE(); |
} |
|
/** |
603,8 → 563,6 |
struct drm_encoder *encoder; |
bool ret = true; |
|
ENTRY(); |
|
adjusted_mode = drm_mode_duplicate(dev, mode); |
|
crtc->enabled = drm_helper_crtc_in_use(crtc); |
696,7 → 654,7 |
crtc->x = saved_x; |
crtc->y = saved_y; |
} |
LEAVE(); |
|
return ret; |
} |
EXPORT_SYMBOL(drm_crtc_helper_set_mode); |
722,18 → 680,17 |
int drm_crtc_helper_set_config(struct drm_mode_set *set) |
{ |
struct drm_device *dev; |
struct drm_crtc **save_crtcs, *new_crtc; |
struct drm_encoder **save_encoders, *new_encoder; |
struct drm_crtc *save_crtcs, *new_crtc, *crtc; |
struct drm_encoder *save_encoders, *new_encoder, *encoder; |
struct drm_framebuffer *old_fb = NULL; |
bool save_enabled; |
bool mode_changed = false; |
bool fb_changed = false; |
struct drm_connector *connector; |
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; |
int count = 0, ro, fail = 0; |
struct drm_crtc_helper_funcs *crtc_funcs; |
int ret = 0; |
|
DRM_DEBUG("\n"); |
DRM_DEBUG_KMS("\n"); |
|
if (!set) |
return -EINVAL; |
746,38 → 703,63 |
|
crtc_funcs = set->crtc->helper_private; |
|
DRM_DEBUG("crtc: %p %d fb: %p connectors: %p num_connectors: %d (x, y) (%i, %i)\n", |
DRM_DEBUG_KMS("crtc: %p %d fb: %p connectors: %p num_connectors:" |
" %d (x, y) (%i, %i)\n", |
set->crtc, set->crtc->base.id, set->fb, set->connectors, |
(int)set->num_connectors, set->x, set->y); |
|
dev = set->crtc->dev; |
|
/* save previous config */ |
save_enabled = set->crtc->enabled; |
|
/* |
* We do mode_config.num_connectors here since we'll look at the |
* CRTC and encoder associated with each connector later. |
*/ |
save_crtcs = kzalloc(dev->mode_config.num_connector * |
sizeof(struct drm_crtc *), GFP_KERNEL); |
/* 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; |
|
save_encoders = kzalloc(dev->mode_config.num_connector * |
sizeof(struct drm_encoders *), GFP_KERNEL); |
save_encoders = kzalloc(dev->mode_config.num_encoder * |
sizeof(struct drm_encoder), GFP_KERNEL); |
if (!save_encoders) { |
kfree(save_crtcs); |
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. |
* 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; |
} |
|
count = 0; |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
save_connectors[count++] = *connector; |
} |
|
/* 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) { |
/* If we have no fb then treat it as a full mode set */ |
if (set->crtc->fb == NULL) { |
DRM_DEBUG("crtc has no fb, full mode set\n"); |
DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); |
mode_changed = true; |
} else if (set->fb == NULL) { |
mode_changed = true; |
} else if ((set->fb->bits_per_pixel != |
set->crtc->fb->bits_per_pixel) || |
set->fb->depth != set->crtc->fb->depth) |
790,7 → 772,7 |
fb_changed = true; |
|
if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { |
DRM_DEBUG("modes are different, full mode set\n"); |
DRM_DEBUG_KMS("modes are different, full mode set\n"); |
drm_mode_debug_printmodeline(&set->crtc->mode); |
drm_mode_debug_printmodeline(set->mode); |
mode_changed = true; |
801,7 → 783,6 |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
struct drm_connector_helper_funcs *connector_funcs = |
connector->helper_private; |
save_encoders[count++] = connector->encoder; |
new_encoder = connector->encoder; |
for (ro = 0; ro < set->num_connectors; ro++) { |
if (set->connectors[ro] == connector) { |
816,8 → 797,13 |
} |
|
if (new_encoder != connector->encoder) { |
DRM_DEBUG("encoder changed, full mode switch\n"); |
DRM_DEBUG_KMS("encoder changed, full mode switch\n"); |
mode_changed = true; |
/* If the encoder is reused for another connector, then |
* the appropriate crtc will be set later. |
*/ |
if (connector->encoder) |
connector->encoder->crtc = NULL; |
connector->encoder = new_encoder; |
} |
} |
824,7 → 810,7 |
|
if (fail) { |
ret = -EINVAL; |
goto fail_no_encoder; |
goto fail; |
} |
|
count = 0; |
832,8 → 818,6 |
if (!connector->encoder) |
continue; |
|
save_crtcs[count++] = connector->encoder->crtc; |
|
if (connector->encoder->crtc == set->crtc) |
new_crtc = NULL; |
else |
848,14 → 832,14 |
if (new_crtc && |
!drm_encoder_crtc_ok(connector->encoder, new_crtc)) { |
ret = -EINVAL; |
goto fail_set_mode; |
goto fail; |
} |
if (new_crtc != connector->encoder->crtc) { |
DRM_DEBUG("crtc changed, full mode switch\n"); |
DRM_DEBUG_KMS("crtc changed, full mode switch\n"); |
mode_changed = true; |
connector->encoder->crtc = new_crtc; |
} |
DRM_DEBUG("setting connector %d crtc to %p\n", |
DRM_DEBUG_KMS("setting connector %d crtc to %p\n", |
connector->base.id, new_crtc); |
} |
|
868,7 → 852,8 |
set->crtc->fb = set->fb; |
set->crtc->enabled = (set->mode != NULL); |
if (set->mode != NULL) { |
DRM_DEBUG("attempting to set mode from userspace\n"); |
DRM_DEBUG_KMS("attempting to set mode from" |
" userspace\n"); |
drm_mode_debug_printmodeline(set->mode); |
if (!drm_crtc_helper_set_mode(set->crtc, set->mode, |
set->x, set->y, |
876,7 → 861,7 |
DRM_ERROR("failed to set mode on crtc %p\n", |
set->crtc); |
ret = -EINVAL; |
goto fail_set_mode; |
goto fail; |
} |
/* TODO are these needed? */ |
set->crtc->desired_x = set->x; |
885,6 → 870,9 |
} |
drm_helper_disable_unused_functions(dev); |
} 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; |
891,30 → 879,34 |
ret = crtc_funcs->mode_set_base(set->crtc, |
set->x, set->y, old_fb); |
if (ret != 0) |
goto fail_set_mode; |
goto fail; |
} |
|
kfree(save_connectors); |
kfree(save_encoders); |
kfree(save_crtcs); |
return 0; |
|
fail_set_mode: |
set->crtc->enabled = save_enabled; |
set->crtc->fb = old_fb; |
fail: |
/* Restore all previous data. */ |
count = 0; |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
if (!connector->encoder) |
continue; |
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
*crtc = save_crtcs[count++]; |
} |
|
connector->encoder->crtc = save_crtcs[count++]; |
count = 0; |
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
*encoder = save_encoders[count++]; |
} |
fail_no_encoder: |
kfree(save_crtcs); |
|
count = 0; |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
connector->encoder = save_encoders[count++]; |
*connector = save_connectors[count++]; |
} |
|
kfree(save_connectors); |
kfree(save_encoders); |
kfree(save_crtcs); |
return ret; |
} |
EXPORT_SYMBOL(drm_crtc_helper_set_config); |
921,7 → 913,7 |
|
bool drm_helper_plugged_event(struct drm_device *dev) |
{ |
DRM_DEBUG("\n"); |
DRM_DEBUG_KMS("\n"); |
|
drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, |
dev->mode_config.max_height); |
950,36 → 942,22 |
*/ |
bool drm_helper_initial_config(struct drm_device *dev) |
{ |
struct drm_connector *connector; |
int count = 0; |
|
ENTRY(); |
|
count = drm_helper_probe_connector_modes(dev, |
dev->mode_config.max_width, |
dev->mode_config.max_height); |
|
/* |
* None of the available connectors had any modes, so add some |
* and try to light them up anyway |
* we shouldn't end up with no modes here. |
*/ |
if (!count) { |
DRM_ERROR("connectors have no modes, using standard modes\n"); |
list_for_each_entry(connector, |
&dev->mode_config.connector_list, |
head) |
drm_helper_add_std_modes(dev, connector); |
} |
// WARN(!count, "Connected connector with 0 modes\n"); |
|
drm_setup_crtcs(dev); |
|
radeonfb_create(dev->dev_private, 1280, 1024, 1280, 1024, NULL); |
|
// /* alert the driver fb layer */ |
/* alert the driver fb layer */ |
dev->mode_config.funcs->fb_changed(dev); |
|
LEAVE(); |
|
return 0; |
} |
EXPORT_SYMBOL(drm_helper_initial_config); |
1100,15 → 1078,13 |
} |
EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); |
|
void sysSetScreen(int width, int height) |
void sysSetScreen(int width, int height, int pitch) |
{ |
asm __volatile__ |
( |
"decl %%eax \n\t" |
"dec %%edx \n\t" |
"call *__imp__SetScreen" |
: |
:"a" (width),"d"(height) |
:"a" (width-1),"d"(height-1), "c"(pitch) |
:"memory","cc" |
); |
} |
1117,33 → 1093,21 |
int drm_helper_resume_force_mode(struct drm_device *dev) |
{ |
struct drm_crtc *crtc; |
struct drm_framebuffer *fb; |
|
int ret; |
|
ENTRY(); |
|
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
|
if (!crtc->enabled) |
continue; |
dbgprintf("mode %x x %x y %x fb %x\n", |
crtc->x, crtc->y, crtc->fb, crtc->mode); |
|
fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); |
|
crtc->fb = fb; |
|
ret = drm_crtc_helper_set_mode(crtc, crtc->desired_mode, |
ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, |
crtc->x, crtc->y, crtc->fb); |
|
if (ret == false) |
DRM_ERROR("failed to set mode on crtc %p\n", crtc); |
|
sysSetScreen(1280,1024); |
|
} |
LEAVE(); |
/* disable the unused connectors while restoring the modesetting */ |
drm_helper_disable_unused_functions(dev); |
return 0; |
} |
EXPORT_SYMBOL(drm_helper_resume_force_mode); |