Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 3479 → Rev 3480

/drivers/video/drm/drm_fb_helper.c
52,9 → 52,36
* 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.
*
* Initialization is done as a three-step process with drm_fb_helper_init(),
* drm_fb_helper_single_add_all_connectors() and drm_fb_helper_initial_config().
* Drivers with fancier requirements than the default beheviour can override the
* second step with their own code. Teardown is done with drm_fb_helper_fini().
*
* At runtime drivers should restore the fbdev console by calling
* drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They
* should also notify the fb helper code from updates to the output
* configuration by calling drm_fb_helper_hotplug_event(). For easier
* integration with the output polling code in drm_crtc_helper.c the modeset
* code proves a ->output_poll_changed callback.
*
* All other functions exported by the fb helper library can be used to
* implement the fbdev driver interface by the driver.
*/
 
/* simple single crtc case helper function */
/**
* drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev
* emulation helper
* @fb_helper: fbdev initialized with drm_fb_helper_init
*
* This functions adds all the available connectors for use with the given
* fb_helper. This is a separate step to allow drivers to freely assign
* connectors to the fbdev, e.g. if some are reserved for special purposes or
* not adequate to be used for the fbcon.
*
* Since this is part of the initial setup before the fbdev is published, no
* locking is required.
*/
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
{
struct drm_device *dev = fb_helper->dev;
110,7 → 137,24
}
 
 
static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
{
struct drm_device *dev = fb_helper->dev;
struct drm_crtc *crtc;
int bound = 0, crtcs_bound = 0;
 
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)
return false;
return true;
}
 
static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
{
struct drm_fb_helper *fb_helper = info->par;
120,9 → 164,20
int i, j;
 
/*
* fbdev->blank can be called from irq context in case of a panic.
* Since we already have our own special panic handler which will
* restore the fbdev console mode completely, just bail out early.
*/
 
/*
* For each CRTC in this fb, turn the connectors on/off.
*/
mutex_lock(&dev->mode_config.mutex);
drm_modeset_lock_all(dev);
if (!drm_fb_helper_is_bound(fb_helper)) {
drm_modeset_unlock_all(dev);
return;
}
 
for (i = 0; i < fb_helper->crtc_count; i++) {
crtc = fb_helper->crtc_info[i].mode_set.crtc;
 
137,9 → 192,14
dev->mode_config.dpms_property, dpms_mode);
}
}
mutex_unlock(&dev->mode_config.mutex);
drm_modeset_unlock_all(dev);
}
 
/**
* drm_fb_helper_blank - implementation for ->fb_blank
* @blank: desired blanking state
* @info: fbdev registered by the helper
*/
int drm_fb_helper_blank(int blank, struct fb_info *info)
{
switch (blank) {
183,6 → 243,24
kfree(helper->crtc_info);
}
 
/**
* drm_fb_helper_init - initialize a drm_fb_helper structure
* @dev: drm device
* @fb_helper: driver-allocated fbdev helper structure to initialize
* @crtc_count: maximum number of crtcs to support in this fbdev emulation
* @max_conn_count: max connector count
*
* This allocates the structures for the fbdev helper with the given limits.
* Note that this won't yet touch the hardware (through the driver interfaces)
* nor register the fbdev. This is only done in drm_fb_helper_initial_config()
* to allow driver writes more control over the exact init sequence.
*
* Drivers must set fb_helper->funcs before calling
* drm_fb_helper_initial_config().
*
* RETURNS:
* Zero if everything went ok, nonzero otherwise.
*/
int drm_fb_helper_init(struct drm_device *dev,
struct drm_fb_helper *fb_helper,
int crtc_count, int max_conn_count)
294,6 → 372,11
return 0;
}
 
/**
* drm_fb_helper_setcmap - implementation for ->fb_setcmap
* @cmap: cmap to set
* @info: fbdev registered by the helper
*/
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
{
struct drm_fb_helper *fb_helper = info->par;
333,6 → 416,11
}
EXPORT_SYMBOL(drm_fb_helper_setcmap);
 
/**
* drm_fb_helper_check_var - implementation for ->fb_check_var
* @var: screeninfo to check
* @info: fbdev registered by the helper
*/
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
425,13 → 513,19
}
EXPORT_SYMBOL(drm_fb_helper_check_var);
 
/* this will let fbcon do the mode init */
/**
* drm_fb_helper_set_par - implementation for ->fb_set_par
* @info: fbdev registered by the helper
*
* This will let fbcon do the mode init and is called at initialization time by
* the fbdev core when registering the driver, and later on through the hotplug
* callback.
*/
int drm_fb_helper_set_par(struct fb_info *info)
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_device *dev = fb_helper->dev;
struct fb_var_screeninfo *var = &info->var;
struct drm_crtc *crtc;
int ret;
int i;
 
440,25 → 534,29
return -EINVAL;
}
 
mutex_lock(&dev->mode_config.mutex);
drm_modeset_lock_all(dev);
for (i = 0; i < fb_helper->crtc_count; i++) {
crtc = fb_helper->crtc_info[i].mode_set.crtc;
ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set);
if (ret) {
mutex_unlock(&dev->mode_config.mutex);
drm_modeset_unlock_all(dev);
return ret;
}
}
mutex_unlock(&dev->mode_config.mutex);
drm_modeset_unlock_all(dev);
 
if (fb_helper->delayed_hotplug) {
fb_helper->delayed_hotplug = false;
// drm_fb_helper_hotplug_event(fb_helper);
drm_fb_helper_hotplug_event(fb_helper);
}
return 0;
}
EXPORT_SYMBOL(drm_fb_helper_set_par);
 
/**
* drm_fb_helper_pan_display - implementation for ->fb_pan_display
* @var: updated screen information
* @info: fbdev registered by the helper
*/
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
469,7 → 567,12
int ret = 0;
int i;
 
mutex_lock(&dev->mode_config.mutex);
drm_modeset_lock_all(dev);
if (!drm_fb_helper_is_bound(fb_helper)) {
drm_modeset_unlock_all(dev);
return -EBUSY;
}
 
for (i = 0; i < fb_helper->crtc_count; i++) {
crtc = fb_helper->crtc_info[i].mode_set.crtc;
 
479,7 → 582,7
modeset->y = var->yoffset;
 
if (modeset->num_connectors) {
ret = crtc->funcs->set_config(modeset);
ret = drm_mode_set_config_internal(modeset);
if (!ret) {
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
486,15 → 589,20
}
}
}
mutex_unlock(&dev->mode_config.mutex);
drm_modeset_unlock_all(dev);
return ret;
}
EXPORT_SYMBOL(drm_fb_helper_pan_display);
 
int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
/*
* Allocates the backing storage and sets up the fbdev info structure through
* the ->fb_probe callback and then registers the fbdev and sets up the panic
* notifier.
*/
static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
int preferred_bpp)
{
int new_fb = 0;
int ret = 0;
int crtc_count = 0;
int i;
struct fb_info *info;
572,34 → 680,44
}
 
/* push down into drivers */
new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
if (new_fb < 0)
return new_fb;
ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
if (ret < 0)
return ret;
 
info = fb_helper->fbdev;
 
/* set the fb pointer */
/*
* Set the fb pointer - usually drm_setup_crtcs does this for hotplug
* events, but at init time drm_setup_crtcs needs to be called before
* the fb is allocated (since we need to figure out the desired size of
* the fb before we can allocate it ...). Hence we need to fix things up
* here again.
*/
for (i = 0; i < fb_helper->crtc_count; i++)
if (fb_helper->crtc_info[i].mode_set.num_connectors)
fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
 
if (new_fb) {
 
info->var.pixclock = 0;
 
// dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
// info->node, info->fix.id);
 
} else {
drm_fb_helper_set_par(info);
}
 
 
if (new_fb)
list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
 
return 0;
}
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
 
/**
* drm_fb_helper_fill_fix - initializes fixed fbdev information
* @info: fbdev registered by the helper
* @pitch: desired pitch
* @depth: desired depth
*
* Helper to fill in the fixed fbdev information useful for a non-accelerated
* fbdev emulations. Drivers which support acceleration methods which impose
* additional constraints need to set up their own limits.
*
* Drivers should call this (or their equivalent setup code) from their
* ->fb_probe callback.
*/
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
uint32_t depth)
{
620,6 → 738,20
}
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
 
/**
* drm_fb_helper_fill_var - initalizes variable fbdev information
* @info: fbdev instance to set up
* @fb_helper: fb helper instance to use as template
* @fb_width: desired fb width
* @fb_height: desired fb height
*
* Sets up the variable fbdev metainformation from the given fb helper instance
* and the drm framebuffer allocated in fb_helper->fb.
*
* Drivers should call this (or their equivalent setup code) from their
* ->fb_probe callback after having allocated the fbdev backing
* storage framebuffer.
*/
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
uint32_t fb_width, uint32_t fb_height)
{
937,6 → 1069,7
for (i = 0; i < fb_helper->crtc_count; i++) {
modeset = &fb_helper->crtc_info[i].mode_set;
modeset->num_connectors = 0;
modeset->fb = NULL;
}
 
for (i = 0; i < fb_helper->connector_count; i++) {
953,9 → 1086,21
modeset->mode = drm_mode_duplicate(dev,
fb_crtc->desired_mode);
modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
modeset->fb = fb_helper->fb;
}
}
 
/* Clear out any old modes if there are no more connected outputs. */
for (i = 0; i < fb_helper->crtc_count; i++) {
modeset = &fb_helper->crtc_info[i].mode_set;
if (modeset->num_connectors == 0) {
BUG_ON(modeset->fb);
BUG_ON(modeset->num_connectors);
if (modeset->mode)
drm_mode_destroy(dev, modeset->mode);
modeset->mode = NULL;
}
}
out:
kfree(crtcs);
kfree(modes);
963,18 → 1108,23
}
 
/**
* drm_helper_initial_config - setup a sane initial connector configuration
* drm_fb_helper_initial_config - setup a sane initial connector configuration
* @fb_helper: fb_helper device struct
* @bpp_sel: bpp value to use for the framebuffer configuration
*
* LOCKING:
* Called at init time by the driver to set up the @fb_helper initial
* configuration, must take the mode config lock.
*
* 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.
*
* Note that this also registers the fbdev and so allows userspace to call into
* the driver through the fbdev interfaces.
*
* This function will call down into the ->fb_probe callback to let
* the driver allocate and initialize the fbdev info structure and the drm
* framebuffer used to back the fbdev. drm_fb_helper_fill_var() and
* drm_fb_helper_fill_fix() are provided as helpers to setup simple default
* values for the fbdev info structure.
*
* RETURNS:
* Zero if everything went ok, nonzero otherwise.
*/
983,9 → 1133,6
struct drm_device *dev = fb_helper->dev;
int count = 0;
 
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(fb_helper->dev);
 
// drm_fb_helper_parse_command_line(fb_helper);
 
count = drm_fb_helper_probe_connector_modes(fb_helper,
1003,18 → 1150,22
}
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.
*
* Called at runtime, takes the mode config locks to be able to check/change the
* modeset configuration. Must be run from process context (which usually means
* either the output polling work or a work item launched from the driver's
* hotplug interrupt).
*
* Note that the driver must ensure that this is only called _after_ the fb has
* been fully set up, i.e. after the call to drm_fb_helper_initial_config.
*
* RETURNS:
* 0 on success and a non-zero error code otherwise.
*/
1023,23 → 1174,14
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) {
mutex_lock(&fb_helper->dev->mode_config.mutex);
if (!drm_fb_helper_is_bound(fb_helper)) {
fb_helper->delayed_hotplug = true;
mutex_unlock(&dev->mode_config.mutex);
mutex_unlock(&fb_helper->dev->mode_config.mutex);
return 0;
}
DRM_DEBUG_KMS("\n");
1050,13 → 1192,16
 
count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
max_height);
mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
drm_modeset_lock_all(dev);
drm_setup_crtcs(fb_helper);
mutex_unlock(&dev->mode_config.mutex);
drm_modeset_unlock_all(dev);
drm_fb_helper_set_par(fb_helper->fbdev);
 
return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
return 0;
}
EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
#endif