27,6 → 27,8 |
* Dave Airlie <airlied@linux.ie> |
* Jesse Barnes <jesse.barnes@intel.com> |
*/ |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|
#include <linux/kernel.h> |
#include <linux/sysrq.h> |
#include <linux/slab.h> |
43,6 → 45,15 |
|
static LIST_HEAD(kernel_fb_helper_list); |
|
/** |
* DOC: fbdev helpers |
* |
* The fb helper functions are useful to provide an fbdev on top of a drm kernel |
* mode setting driver. They can be used mostly independantely from the crtc |
* helper functions used by many drivers to implement the kernel mode setting |
* interfaces. |
*/ |
|
/* simple single crtc case helper function */ |
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) |
{ |
50,6 → 61,8 |
struct drm_connector *connector; |
int i; |
|
ENTER(); |
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
struct drm_fb_helper_connector *fb_helper_connector; |
|
60,6 → 73,7 |
fb_helper_connector->connector = connector; |
fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; |
} |
LEAVE(); |
return 0; |
fail: |
for (i = 0; i < fb_helper->connector_count; i++) { |
67,6 → 81,7 |
fb_helper->connector_info[i] = NULL; |
} |
fb_helper->connector_count = 0; |
FAIL(); |
return -ENOMEM; |
} |
EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); |
122,7 → 137,7 |
for (j = 0; j < fb_helper->connector_count; j++) { |
connector = fb_helper->connector_info[j]->connector; |
connector->funcs->dpms(connector, dpms_mode); |
drm_connector_property_set_value(connector, |
drm_object_property_set_value(&connector->base, |
dev->mode_config.dpms_property, dpms_mode); |
} |
} |
179,6 → 194,10 |
struct drm_crtc *crtc; |
int i; |
|
ENTER(); |
|
dbgprintf("crtc_count %d max_conn_count %d\n", crtc_count, max_conn_count); |
|
fb_helper->dev = dev; |
|
INIT_LIST_HEAD(&fb_helper->kernel_fb_list); |
185,12 → 204,16 |
|
fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); |
if (!fb_helper->crtc_info) |
{ |
FAIL(); |
return -ENOMEM; |
}; |
|
fb_helper->crtc_count = crtc_count; |
fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); |
if (!fb_helper->connector_info) { |
kfree(fb_helper->crtc_info); |
FAIL(); |
return -ENOMEM; |
} |
fb_helper->connector_count = 0; |
212,9 → 235,11 |
i++; |
} |
|
LEAVE(); |
return 0; |
out_free: |
drm_fb_helper_crtc_free(fb_helper); |
FAIL(); |
return -ENOMEM; |
} |
EXPORT_SYMBOL(drm_fb_helper_init); |
498,9 → 523,9 |
|
/* if driver picks 8 or 16 by default use that |
for both depth/bpp */ |
if (preferred_bpp != sizes.surface_bpp) { |
if (preferred_bpp != sizes.surface_bpp) |
sizes.surface_depth = sizes.surface_bpp = preferred_bpp; |
} |
|
/* first up get a count of crtcs now in use and new min/maxes width/heights */ |
for (i = 0; i < fb_helper->connector_count; i++) { |
struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; |
568,9 → 593,8 |
info = fb_helper->fbdev; |
|
/* set the fb pointer */ |
for (i = 0; i < fb_helper->crtc_count; i++) { |
for (i = 0; i < fb_helper->crtc_count; i++) |
fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; |
} |
|
if (new_fb) { |
info->var.pixclock = 0; |
726,11 → 750,11 |
{ |
bool enable; |
|
if (strict) { |
if (strict) |
enable = connector->status == connector_status_connected; |
} else { |
else |
enable = connector->status != connector_status_disconnected; |
} |
|
return enable; |
} |
|
846,9 → 870,8 |
for (c = 0; c < fb_helper->crtc_count; c++) { |
crtc = &fb_helper->crtc_info[c]; |
|
if ((encoder->possible_crtcs & (1 << c)) == 0) { |
if ((encoder->possible_crtcs & (1 << c)) == 0) |
continue; |
} |
|
for (o = 0; o < n; o++) |
if (best_crtcs[o] == crtc) |
901,7 → 924,12 |
sizeof(struct drm_display_mode *), GFP_KERNEL); |
enabled = kcalloc(dev->mode_config.num_connector, |
sizeof(bool), GFP_KERNEL); |
if (!crtcs || !modes || !enabled) { |
DRM_ERROR("Memory allocation failed\n"); |
goto out; |
} |
|
|
drm_enable_connectors(fb_helper, enabled); |
|
//ret = drm_target_cloned(fb_helper, modes, enabled, width, height); |
942,6 → 970,7 |
} |
} |
|
out: |
kfree(crtcs); |
kfree(modes); |
kfree(enabled); |
949,12 → 978,14 |
|
/** |
* drm_helper_initial_config - setup a sane initial connector configuration |
* @dev: DRM device |
* @fb_helper: fb_helper device struct |
* @bpp_sel: bpp value to use for the framebuffer configuration |
* |
* LOCKING: |
* Called at init time, must take mode config lock. |
* Called at init time by the driver to set up the @fb_helper initial |
* configuration, must take the mode config lock. |
* |
* Scan the CRTCs and connectors and try to put together an initial setup. |
* Scans the CRTCs and connectors and tries to put together an initial setup. |
* At the moment, this is a cloned configuration across all heads with |
* a new framebuffer object as the backing store. |
* |
965,7 → 996,10 |
{ |
struct drm_device *dev = fb_helper->dev; |
int count = 0; |
bool ret; |
|
ENTER(); |
|
/* disable all the possible outputs/crtcs before entering KMS mode */ |
drm_helper_disable_unused_functions(fb_helper->dev); |
|
977,11 → 1011,70 |
/* |
* we shouldn't end up with no modes here. |
*/ |
if (count == 0) { |
printk(KERN_INFO "No connectors reported connected with modes\n"); |
if (count == 0) |
dev_info(fb_helper->dev->dev, "No connectors reported connected with modes\n"); |
|
drm_setup_crtcs(fb_helper); |
|
ret = drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); |
LEAVE(); |
} |
EXPORT_SYMBOL(drm_fb_helper_initial_config); |
|
#if 0 |
/** |
* drm_fb_helper_hotplug_event - respond to a hotplug notification by |
* probing all the outputs attached to the fb |
* @fb_helper: the drm_fb_helper |
* |
* LOCKING: |
* Called at runtime, must take mode config lock. |
* |
* Scan the connectors attached to the fb_helper and try to put together a |
* setup after *notification of a change in output configuration. |
* |
* RETURNS: |
* 0 on success and a non-zero error code otherwise. |
*/ |
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) |
{ |
struct drm_device *dev = fb_helper->dev; |
int count = 0; |
u32 max_width, max_height, bpp_sel; |
int bound = 0, crtcs_bound = 0; |
struct drm_crtc *crtc; |
|
if (!fb_helper->fb) |
return 0; |
|
mutex_lock(&dev->mode_config.mutex); |
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
if (crtc->fb) |
crtcs_bound++; |
if (crtc->fb == fb_helper->fb) |
bound++; |
} |
|
if (bound < crtcs_bound) { |
fb_helper->delayed_hotplug = true; |
mutex_unlock(&dev->mode_config.mutex); |
return 0; |
} |
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); |
drm_setup_crtcs(fb_helper); |
mutex_unlock(&dev->mode_config.mutex); |
|
return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); |
} |
EXPORT_SYMBOL(drm_fb_helper_initial_config); |
EXPORT_SYMBOL(drm_fb_helper_hotplug_event); |
#endif |
|
|
|