mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:02:20 +00:00
drm/fb-helper: Remove drm_fb_helper_crtc
struct drm_fb_helper_crtc is now just a wrapper around drm_mode_set so use that directly instead and attach it as a modeset array onto drm_client_dev. drm_fb_helper will use this array to store its modesets which means it will always initialize a drm_client, but it will not register the client (callbacks) unless it's the generic fbdev emulation. Code will later be moved to drm_client, so add code there in a new file drm_client_modeset.c with MIT license to match drm_fb_helper.c. The modeset connector array size is hardcoded for the cloned case to avoid having to pass in a value from the driver. A value of 8 is chosen to err on the safe side. This means that the max connector argument for drm_fb_helper_init() and drm_fb_helper_fbdev_setup() isn't used anymore, a todo entry for this is added. In pan_display_atomic() restore_fbdev_mode_force() is used instead of restore_fbdev_mode_atomic() because that one will later become internal to drm_client_modeset. Locking order: 1. drm_fb_helper->lock 2. drm_master_internal_acquire 3. drm_client_dev->modeset_mutex v6: Improve commit message (Sam Ravnborg) v3: - Use full drm_client_init/release for the modesets (Daniel Vetter) - drm_client_for_each_modeset: use lockdep_assert_held (Daniel Vetter) - Hook up to Documentation/gpu/drm-client.rst (Daniel Vetter) v2: - Add modesets array to drm_client (Daniel Vetter) - Use a new file for the modeset code (Daniel Vetter) - File has to be MIT licensed (Emmanuel Vadot) - Add copyrights from drm_fb_helper.c Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: Sam Ravnborg <sam@ravnborg.org> Link: https://patchwork.freedesktop.org/patch/msgid/20190531140117.37751-3-noralf@tronnes.org
This commit is contained in:
parent
1b94f47793
commit
d81294afee
@ -10,3 +10,6 @@ Kernel clients
|
|||||||
|
|
||||||
.. kernel-doc:: drivers/gpu/drm/drm_client.c
|
.. kernel-doc:: drivers/gpu/drm/drm_client.c
|
||||||
:export:
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/gpu/drm/drm_client_modeset.c
|
||||||
|
:export:
|
||||||
|
@ -289,6 +289,9 @@ drm_fb_helper tasks
|
|||||||
these igt tests need to be fixed: kms_fbcon_fbt@psr and
|
these igt tests need to be fixed: kms_fbcon_fbt@psr and
|
||||||
kms_fbcon_fbt@psr-suspend.
|
kms_fbcon_fbt@psr-suspend.
|
||||||
|
|
||||||
|
- The max connector argument for drm_fb_helper_init() and
|
||||||
|
drm_fb_helper_fbdev_setup() isn't used anymore and can be removed.
|
||||||
|
|
||||||
Core refactorings
|
Core refactorings
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ drm-y := drm_auth.o drm_cache.o \
|
|||||||
drm_plane.o drm_color_mgmt.o drm_print.o \
|
drm_plane.o drm_color_mgmt.o drm_print.o \
|
||||||
drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
|
drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
|
||||||
drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \
|
drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \
|
||||||
drm_atomic_uapi.o drm_hdcp.o
|
drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o
|
||||||
|
|
||||||
drm-$(CONFIG_DRM_LEGACY) += drm_legacy_misc.o drm_bufs.o drm_context.o drm_dma.o drm_scatter.o drm_lock.o
|
drm-$(CONFIG_DRM_LEGACY) += drm_legacy_misc.o drm_bufs.o drm_context.o drm_dma.o drm_scatter.o drm_lock.o
|
||||||
drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
|
drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
* DOC: overview
|
* DOC: overview
|
||||||
*
|
*
|
||||||
* This library provides support for clients running in the kernel like fbdev and bootsplash.
|
* This library provides support for clients running in the kernel like fbdev and bootsplash.
|
||||||
* Currently it's only partially implemented, just enough to support fbdev.
|
|
||||||
*
|
*
|
||||||
* GEM drivers which provide a GEM based dumb buffer with a virtual address are supported.
|
* GEM drivers which provide a GEM based dumb buffer with a virtual address are supported.
|
||||||
*/
|
*/
|
||||||
@ -92,14 +91,20 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
|
|||||||
client->name = name;
|
client->name = name;
|
||||||
client->funcs = funcs;
|
client->funcs = funcs;
|
||||||
|
|
||||||
ret = drm_client_open(client);
|
ret = drm_client_modeset_create(client);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_put_module;
|
goto err_put_module;
|
||||||
|
|
||||||
|
ret = drm_client_open(client);
|
||||||
|
if (ret)
|
||||||
|
goto err_free;
|
||||||
|
|
||||||
drm_dev_get(dev);
|
drm_dev_get(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
drm_client_modeset_free(client);
|
||||||
err_put_module:
|
err_put_module:
|
||||||
if (funcs)
|
if (funcs)
|
||||||
module_put(funcs->owner);
|
module_put(funcs->owner);
|
||||||
@ -148,6 +153,7 @@ void drm_client_release(struct drm_client_dev *client)
|
|||||||
|
|
||||||
DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name);
|
DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name);
|
||||||
|
|
||||||
|
drm_client_modeset_free(client);
|
||||||
drm_client_close(client);
|
drm_client_close(client);
|
||||||
drm_dev_put(dev);
|
drm_dev_put(dev);
|
||||||
if (client->funcs)
|
if (client->funcs)
|
||||||
|
104
drivers/gpu/drm/drm_client_modeset.c
Normal file
104
drivers/gpu/drm/drm_client_modeset.c
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Noralf Trønnes
|
||||||
|
* Copyright (c) 2006-2009 Red Hat Inc.
|
||||||
|
* Copyright (c) 2006-2008 Intel Corporation
|
||||||
|
* Jesse Barnes <jesse.barnes@intel.com>
|
||||||
|
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include <drm/drm_client.h>
|
||||||
|
#include <drm/drm_crtc.h>
|
||||||
|
#include <drm/drm_device.h>
|
||||||
|
|
||||||
|
int drm_client_modeset_create(struct drm_client_dev *client)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = client->dev;
|
||||||
|
unsigned int num_crtc = dev->mode_config.num_crtc;
|
||||||
|
unsigned int max_connector_count = 1;
|
||||||
|
struct drm_mode_set *modeset;
|
||||||
|
struct drm_crtc *crtc;
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
/* Add terminating zero entry to enable index less iteration */
|
||||||
|
client->modesets = kcalloc(num_crtc + 1, sizeof(*client->modesets), GFP_KERNEL);
|
||||||
|
if (!client->modesets)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mutex_init(&client->modeset_mutex);
|
||||||
|
|
||||||
|
drm_for_each_crtc(crtc, dev)
|
||||||
|
client->modesets[i++].crtc = crtc;
|
||||||
|
|
||||||
|
/* Cloning is only supported in the single crtc case. */
|
||||||
|
if (num_crtc == 1)
|
||||||
|
max_connector_count = DRM_CLIENT_MAX_CLONED_CONNECTORS;
|
||||||
|
|
||||||
|
for (modeset = client->modesets; modeset->crtc; modeset++) {
|
||||||
|
modeset->connectors = kcalloc(max_connector_count,
|
||||||
|
sizeof(*modeset->connectors), GFP_KERNEL);
|
||||||
|
if (!modeset->connectors)
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
drm_client_modeset_free(client);
|
||||||
|
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drm_client_modeset_release(struct drm_client_dev *client)
|
||||||
|
{
|
||||||
|
struct drm_mode_set *modeset;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
drm_client_for_each_modeset(modeset, client) {
|
||||||
|
drm_mode_destroy(client->dev, modeset->mode);
|
||||||
|
modeset->mode = NULL;
|
||||||
|
modeset->fb = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < modeset->num_connectors; i++) {
|
||||||
|
drm_connector_put(modeset->connectors[i]);
|
||||||
|
modeset->connectors[i] = NULL;
|
||||||
|
}
|
||||||
|
modeset->num_connectors = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* TODO: Remove export when modeset code has been moved over */
|
||||||
|
EXPORT_SYMBOL(drm_client_modeset_release);
|
||||||
|
|
||||||
|
void drm_client_modeset_free(struct drm_client_dev *client)
|
||||||
|
{
|
||||||
|
struct drm_mode_set *modeset;
|
||||||
|
|
||||||
|
mutex_lock(&client->modeset_mutex);
|
||||||
|
|
||||||
|
drm_client_modeset_release(client);
|
||||||
|
|
||||||
|
drm_client_for_each_modeset(modeset, client)
|
||||||
|
kfree(modeset->connectors);
|
||||||
|
|
||||||
|
mutex_unlock(&client->modeset_mutex);
|
||||||
|
|
||||||
|
mutex_destroy(&client->modeset_mutex);
|
||||||
|
kfree(client->modesets);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_mode_set *modeset;
|
||||||
|
|
||||||
|
drm_client_for_each_modeset(modeset, client)
|
||||||
|
if (modeset->crtc == crtc)
|
||||||
|
return modeset;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* TODO: Remove export when modeset code has been moved over */
|
||||||
|
EXPORT_SYMBOL(drm_client_find_modeset);
|
@ -322,13 +322,11 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
|
|||||||
{
|
{
|
||||||
struct drm_fb_helper *helper = info->par;
|
struct drm_fb_helper *helper = info->par;
|
||||||
const struct drm_crtc_helper_funcs *funcs;
|
const struct drm_crtc_helper_funcs *funcs;
|
||||||
int i;
|
struct drm_mode_set *mode_set;
|
||||||
|
|
||||||
list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
|
list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
|
||||||
for (i = 0; i < helper->crtc_count; i++) {
|
mutex_lock(&helper->client.modeset_mutex);
|
||||||
struct drm_mode_set *mode_set =
|
drm_client_for_each_modeset(mode_set, &helper->client) {
|
||||||
&helper->crtc_info[i].mode_set;
|
|
||||||
|
|
||||||
if (!mode_set->crtc->enabled)
|
if (!mode_set->crtc->enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -345,6 +343,7 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
|
|||||||
mode_set->y,
|
mode_set->y,
|
||||||
ENTER_ATOMIC_MODE_SET);
|
ENTER_ATOMIC_MODE_SET);
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&helper->client.modeset_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -358,14 +357,14 @@ EXPORT_SYMBOL(drm_fb_helper_debug_enter);
|
|||||||
int drm_fb_helper_debug_leave(struct fb_info *info)
|
int drm_fb_helper_debug_leave(struct fb_info *info)
|
||||||
{
|
{
|
||||||
struct drm_fb_helper *helper = info->par;
|
struct drm_fb_helper *helper = info->par;
|
||||||
|
struct drm_client_dev *client = &helper->client;
|
||||||
struct drm_crtc *crtc;
|
struct drm_crtc *crtc;
|
||||||
const struct drm_crtc_helper_funcs *funcs;
|
const struct drm_crtc_helper_funcs *funcs;
|
||||||
|
struct drm_mode_set *mode_set;
|
||||||
struct drm_framebuffer *fb;
|
struct drm_framebuffer *fb;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < helper->crtc_count; i++) {
|
|
||||||
struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
|
|
||||||
|
|
||||||
|
mutex_lock(&client->modeset_mutex);
|
||||||
|
drm_client_for_each_modeset(mode_set, client) {
|
||||||
crtc = mode_set->crtc;
|
crtc = mode_set->crtc;
|
||||||
if (drm_drv_uses_atomic_modeset(crtc->dev))
|
if (drm_drv_uses_atomic_modeset(crtc->dev))
|
||||||
continue;
|
continue;
|
||||||
@ -388,6 +387,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
|
|||||||
funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
|
funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
|
||||||
crtc->y, LEAVE_ATOMIC_MODE_SET);
|
crtc->y, LEAVE_ATOMIC_MODE_SET);
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&client->modeset_mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -438,12 +438,14 @@ static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
|
|||||||
|
|
||||||
static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
|
static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
|
||||||
{
|
{
|
||||||
|
struct drm_client_dev *client = &fb_helper->client;
|
||||||
struct drm_device *dev = fb_helper->dev;
|
struct drm_device *dev = fb_helper->dev;
|
||||||
struct drm_plane_state *plane_state;
|
struct drm_plane_state *plane_state;
|
||||||
struct drm_plane *plane;
|
struct drm_plane *plane;
|
||||||
struct drm_atomic_state *state;
|
struct drm_atomic_state *state;
|
||||||
int i, ret;
|
|
||||||
struct drm_modeset_acquire_ctx ctx;
|
struct drm_modeset_acquire_ctx ctx;
|
||||||
|
struct drm_mode_set *mode_set;
|
||||||
|
int ret;
|
||||||
|
|
||||||
drm_modeset_acquire_init(&ctx, 0);
|
drm_modeset_acquire_init(&ctx, 0);
|
||||||
|
|
||||||
@ -473,8 +475,7 @@ retry:
|
|||||||
goto out_state;
|
goto out_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
drm_client_for_each_modeset(mode_set, client) {
|
||||||
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
|
|
||||||
struct drm_plane *primary = mode_set->crtc->primary;
|
struct drm_plane *primary = mode_set->crtc->primary;
|
||||||
unsigned int rotation;
|
unsigned int rotation;
|
||||||
|
|
||||||
@ -522,9 +523,11 @@ backoff:
|
|||||||
|
|
||||||
static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
|
static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
|
||||||
{
|
{
|
||||||
|
struct drm_client_dev *client = &fb_helper->client;
|
||||||
struct drm_device *dev = fb_helper->dev;
|
struct drm_device *dev = fb_helper->dev;
|
||||||
|
struct drm_mode_set *mode_set;
|
||||||
struct drm_plane *plane;
|
struct drm_plane *plane;
|
||||||
int i, ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
drm_modeset_lock_all(fb_helper->dev);
|
drm_modeset_lock_all(fb_helper->dev);
|
||||||
drm_for_each_plane(plane, dev) {
|
drm_for_each_plane(plane, dev) {
|
||||||
@ -537,8 +540,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
|
|||||||
DRM_MODE_ROTATE_0);
|
DRM_MODE_ROTATE_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
drm_client_for_each_modeset(mode_set, client) {
|
||||||
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
|
|
||||||
struct drm_crtc *crtc = mode_set->crtc;
|
struct drm_crtc *crtc = mode_set->crtc;
|
||||||
|
|
||||||
if (crtc->funcs->cursor_set2) {
|
if (crtc->funcs->cursor_set2) {
|
||||||
@ -564,11 +566,16 @@ out:
|
|||||||
static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)
|
static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = fb_helper->dev;
|
struct drm_device *dev = fb_helper->dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&fb_helper->client.modeset_mutex);
|
||||||
if (drm_drv_uses_atomic_modeset(dev))
|
if (drm_drv_uses_atomic_modeset(dev))
|
||||||
return restore_fbdev_mode_atomic(fb_helper, true);
|
ret = restore_fbdev_mode_atomic(fb_helper, true);
|
||||||
else
|
else
|
||||||
return restore_fbdev_mode_legacy(fb_helper);
|
ret = restore_fbdev_mode_legacy(fb_helper);
|
||||||
|
mutex_unlock(&fb_helper->client.modeset_mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
|
static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
|
||||||
@ -687,15 +694,14 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
|
|||||||
|
|
||||||
static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
|
static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
|
||||||
{
|
{
|
||||||
|
struct drm_client_dev *client = &fb_helper->client;
|
||||||
struct drm_device *dev = fb_helper->dev;
|
struct drm_device *dev = fb_helper->dev;
|
||||||
struct drm_connector *connector;
|
struct drm_connector *connector;
|
||||||
struct drm_mode_set *modeset;
|
struct drm_mode_set *modeset;
|
||||||
int i, j;
|
int j;
|
||||||
|
|
||||||
drm_modeset_lock_all(dev);
|
drm_modeset_lock_all(dev);
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
drm_client_for_each_modeset(modeset, client) {
|
||||||
modeset = &fb_helper->crtc_info[i].mode_set;
|
|
||||||
|
|
||||||
if (!modeset->crtc->enabled)
|
if (!modeset->crtc->enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -712,6 +718,7 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
|
|||||||
static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
|
static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
|
||||||
{
|
{
|
||||||
struct drm_fb_helper *fb_helper = info->par;
|
struct drm_fb_helper *fb_helper = info->par;
|
||||||
|
struct drm_client_dev *client = &fb_helper->client;
|
||||||
struct drm_device *dev = fb_helper->dev;
|
struct drm_device *dev = fb_helper->dev;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -721,10 +728,12 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
|
|||||||
if (!drm_master_internal_acquire(dev))
|
if (!drm_master_internal_acquire(dev))
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
|
mutex_lock(&client->modeset_mutex);
|
||||||
if (drm_drv_uses_atomic_modeset(dev))
|
if (drm_drv_uses_atomic_modeset(dev))
|
||||||
restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
|
restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
|
||||||
else
|
else
|
||||||
dpms_legacy(fb_helper, dpms_mode);
|
dpms_legacy(fb_helper, dpms_mode);
|
||||||
|
mutex_unlock(&client->modeset_mutex);
|
||||||
|
|
||||||
drm_master_internal_release(dev);
|
drm_master_internal_release(dev);
|
||||||
unlock:
|
unlock:
|
||||||
@ -767,43 +776,6 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_fb_helper_blank);
|
EXPORT_SYMBOL(drm_fb_helper_blank);
|
||||||
|
|
||||||
static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper,
|
|
||||||
struct drm_mode_set *modeset)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < modeset->num_connectors; i++) {
|
|
||||||
drm_connector_put(modeset->connectors[i]);
|
|
||||||
modeset->connectors[i] = NULL;
|
|
||||||
}
|
|
||||||
modeset->num_connectors = 0;
|
|
||||||
|
|
||||||
drm_mode_destroy(helper->dev, modeset->mode);
|
|
||||||
modeset->mode = NULL;
|
|
||||||
|
|
||||||
/* FIXME should hold a ref? */
|
|
||||||
modeset->fb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < helper->connector_count; i++) {
|
|
||||||
drm_connector_put(helper->connector_info[i]->connector);
|
|
||||||
kfree(helper->connector_info[i]);
|
|
||||||
}
|
|
||||||
kfree(helper->connector_info);
|
|
||||||
|
|
||||||
for (i = 0; i < helper->crtc_count; i++) {
|
|
||||||
struct drm_mode_set *modeset = &helper->crtc_info[i].mode_set;
|
|
||||||
|
|
||||||
drm_fb_helper_modeset_release(helper, modeset);
|
|
||||||
kfree(modeset->connectors);
|
|
||||||
}
|
|
||||||
kfree(helper->crtc_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drm_fb_helper_resume_worker(struct work_struct *work)
|
static void drm_fb_helper_resume_worker(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
|
struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
|
||||||
@ -882,7 +854,7 @@ EXPORT_SYMBOL(drm_fb_helper_prepare);
|
|||||||
* drm_fb_helper_init - initialize a &struct drm_fb_helper
|
* drm_fb_helper_init - initialize a &struct drm_fb_helper
|
||||||
* @dev: drm device
|
* @dev: drm device
|
||||||
* @fb_helper: driver-allocated fbdev helper structure to initialize
|
* @fb_helper: driver-allocated fbdev helper structure to initialize
|
||||||
* @max_conn_count: max connector count
|
* @max_conn_count: max connector count (not used)
|
||||||
*
|
*
|
||||||
* This allocates the structures for the fbdev helper with the given limits.
|
* 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)
|
* Note that this won't yet touch the hardware (through the driver interfaces)
|
||||||
@ -898,53 +870,36 @@ int drm_fb_helper_init(struct drm_device *dev,
|
|||||||
struct drm_fb_helper *fb_helper,
|
struct drm_fb_helper *fb_helper,
|
||||||
int max_conn_count)
|
int max_conn_count)
|
||||||
{
|
{
|
||||||
struct drm_crtc *crtc;
|
int ret;
|
||||||
struct drm_mode_config *config = &dev->mode_config;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!drm_fbdev_emulation) {
|
if (!drm_fbdev_emulation) {
|
||||||
dev->fb_helper = fb_helper;
|
dev->fb_helper = fb_helper;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!max_conn_count)
|
/*
|
||||||
return -EINVAL;
|
* If this is not the generic fbdev client, initialize a drm_client
|
||||||
|
* without callbacks so we can use the modesets.
|
||||||
fb_helper->crtc_info = kcalloc(config->num_crtc, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
|
*/
|
||||||
if (!fb_helper->crtc_info)
|
if (!fb_helper->client.funcs) {
|
||||||
return -ENOMEM;
|
ret = drm_client_init(dev, &fb_helper->client, "drm_fb_helper", NULL);
|
||||||
|
if (ret)
|
||||||
fb_helper->crtc_count = config->num_crtc;
|
return ret;
|
||||||
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);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
|
||||||
|
if (!fb_helper->connector_info)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
|
fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
|
||||||
fb_helper->connector_count = 0;
|
fb_helper->connector_count = 0;
|
||||||
|
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
|
||||||
fb_helper->crtc_info[i].mode_set.connectors =
|
|
||||||
kcalloc(max_conn_count,
|
|
||||||
sizeof(struct drm_connector *),
|
|
||||||
GFP_KERNEL);
|
|
||||||
|
|
||||||
if (!fb_helper->crtc_info[i].mode_set.connectors)
|
|
||||||
goto out_free;
|
|
||||||
fb_helper->crtc_info[i].mode_set.num_connectors = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
drm_for_each_crtc(crtc, dev) {
|
|
||||||
fb_helper->crtc_info[i].mode_set.crtc = crtc;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->fb_helper = fb_helper;
|
dev->fb_helper = fb_helper;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out_free:
|
out_free:
|
||||||
drm_fb_helper_crtc_free(fb_helper);
|
drm_client_release(&fb_helper->client);
|
||||||
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_fb_helper_init);
|
EXPORT_SYMBOL(drm_fb_helper_init);
|
||||||
@ -1020,6 +975,7 @@ EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
|
|||||||
void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
|
void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
|
||||||
{
|
{
|
||||||
struct fb_info *info;
|
struct fb_info *info;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (!fb_helper)
|
if (!fb_helper)
|
||||||
return;
|
return;
|
||||||
@ -1049,8 +1005,15 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
|
|||||||
mutex_unlock(&kernel_fb_helper_lock);
|
mutex_unlock(&kernel_fb_helper_lock);
|
||||||
|
|
||||||
mutex_destroy(&fb_helper->lock);
|
mutex_destroy(&fb_helper->lock);
|
||||||
drm_fb_helper_crtc_free(fb_helper);
|
|
||||||
|
|
||||||
|
if (!fb_helper->client.funcs)
|
||||||
|
drm_client_release(&fb_helper->client);
|
||||||
|
|
||||||
|
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||||
|
drm_connector_put(fb_helper->connector_info[i]->connector);
|
||||||
|
kfree(fb_helper->connector_info[i]);
|
||||||
|
}
|
||||||
|
kfree(fb_helper->connector_info);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_fb_helper_fini);
|
EXPORT_SYMBOL(drm_fb_helper_fini);
|
||||||
|
|
||||||
@ -1395,13 +1358,14 @@ static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
|
|||||||
static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
|
static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
|
||||||
{
|
{
|
||||||
struct drm_fb_helper *fb_helper = info->par;
|
struct drm_fb_helper *fb_helper = info->par;
|
||||||
|
struct drm_mode_set *modeset;
|
||||||
struct drm_crtc *crtc;
|
struct drm_crtc *crtc;
|
||||||
u16 *r, *g, *b;
|
u16 *r, *g, *b;
|
||||||
int i, ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
drm_modeset_lock_all(fb_helper->dev);
|
drm_modeset_lock_all(fb_helper->dev);
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
drm_client_for_each_modeset(modeset, &fb_helper->client) {
|
||||||
crtc = fb_helper->crtc_info[i].mode_set.crtc;
|
crtc = modeset->crtc;
|
||||||
if (!crtc->funcs->gamma_set || !crtc->gamma_size)
|
if (!crtc->funcs->gamma_set || !crtc->gamma_size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -1477,10 +1441,11 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
|
|||||||
struct drm_modeset_acquire_ctx ctx;
|
struct drm_modeset_acquire_ctx ctx;
|
||||||
struct drm_crtc_state *crtc_state;
|
struct drm_crtc_state *crtc_state;
|
||||||
struct drm_atomic_state *state;
|
struct drm_atomic_state *state;
|
||||||
|
struct drm_mode_set *modeset;
|
||||||
struct drm_crtc *crtc;
|
struct drm_crtc *crtc;
|
||||||
u16 *r, *g, *b;
|
u16 *r, *g, *b;
|
||||||
int i, ret = 0;
|
|
||||||
bool replaced;
|
bool replaced;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
drm_modeset_acquire_init(&ctx, 0);
|
drm_modeset_acquire_init(&ctx, 0);
|
||||||
|
|
||||||
@ -1492,8 +1457,8 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
|
|||||||
|
|
||||||
state->acquire_ctx = &ctx;
|
state->acquire_ctx = &ctx;
|
||||||
retry:
|
retry:
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
drm_client_for_each_modeset(modeset, &fb_helper->client) {
|
||||||
crtc = fb_helper->crtc_info[i].mode_set.crtc;
|
crtc = modeset->crtc;
|
||||||
|
|
||||||
if (!gamma_lut)
|
if (!gamma_lut)
|
||||||
gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
|
gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
|
||||||
@ -1521,8 +1486,8 @@ retry:
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out_state;
|
goto out_state;
|
||||||
|
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
drm_client_for_each_modeset(modeset, &fb_helper->client) {
|
||||||
crtc = fb_helper->crtc_info[i].mode_set.crtc;
|
crtc = modeset->crtc;
|
||||||
|
|
||||||
r = crtc->gamma_store;
|
r = crtc->gamma_store;
|
||||||
g = r + crtc->gamma_size;
|
g = r + crtc->gamma_size;
|
||||||
@ -1572,12 +1537,14 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
|
|||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&fb_helper->client.modeset_mutex);
|
||||||
if (info->fix.visual == FB_VISUAL_TRUECOLOR)
|
if (info->fix.visual == FB_VISUAL_TRUECOLOR)
|
||||||
ret = setcmap_pseudo_palette(cmap, info);
|
ret = setcmap_pseudo_palette(cmap, info);
|
||||||
else if (drm_drv_uses_atomic_modeset(fb_helper->dev))
|
else if (drm_drv_uses_atomic_modeset(fb_helper->dev))
|
||||||
ret = setcmap_atomic(cmap, info);
|
ret = setcmap_atomic(cmap, info);
|
||||||
else
|
else
|
||||||
ret = setcmap_legacy(cmap, info);
|
ret = setcmap_legacy(cmap, info);
|
||||||
|
mutex_unlock(&fb_helper->client.modeset_mutex);
|
||||||
|
|
||||||
drm_master_internal_release(dev);
|
drm_master_internal_release(dev);
|
||||||
unlock:
|
unlock:
|
||||||
@ -1601,7 +1568,6 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
|
|||||||
{
|
{
|
||||||
struct drm_fb_helper *fb_helper = info->par;
|
struct drm_fb_helper *fb_helper = info->par;
|
||||||
struct drm_device *dev = fb_helper->dev;
|
struct drm_device *dev = fb_helper->dev;
|
||||||
struct drm_mode_set *mode_set;
|
|
||||||
struct drm_crtc *crtc;
|
struct drm_crtc *crtc;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@ -1629,8 +1595,7 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
|
|||||||
* make. If we're not smart enough here, one should
|
* make. If we're not smart enough here, one should
|
||||||
* just consider switch the userspace to KMS.
|
* just consider switch the userspace to KMS.
|
||||||
*/
|
*/
|
||||||
mode_set = &fb_helper->crtc_info[0].mode_set;
|
crtc = fb_helper->client.modesets[0].crtc;
|
||||||
crtc = mode_set->crtc;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only wait for a vblank event if the CRTC is
|
* Only wait for a vblank event if the CRTC is
|
||||||
@ -1827,16 +1792,14 @@ EXPORT_SYMBOL(drm_fb_helper_set_par);
|
|||||||
|
|
||||||
static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
|
static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
|
||||||
{
|
{
|
||||||
int i;
|
struct drm_mode_set *mode_set;
|
||||||
|
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
|
||||||
struct drm_mode_set *mode_set;
|
|
||||||
|
|
||||||
mode_set = &fb_helper->crtc_info[i].mode_set;
|
|
||||||
|
|
||||||
|
mutex_lock(&fb_helper->client.modeset_mutex);
|
||||||
|
drm_client_for_each_modeset(mode_set, &fb_helper->client) {
|
||||||
mode_set->x = x;
|
mode_set->x = x;
|
||||||
mode_set->y = y;
|
mode_set->y = y;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&fb_helper->client.modeset_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pan_display_atomic(struct fb_var_screeninfo *var,
|
static int pan_display_atomic(struct fb_var_screeninfo *var,
|
||||||
@ -1847,7 +1810,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
|
|||||||
|
|
||||||
pan_set(fb_helper, var->xoffset, var->yoffset);
|
pan_set(fb_helper, var->xoffset, var->yoffset);
|
||||||
|
|
||||||
ret = restore_fbdev_mode_atomic(fb_helper, true);
|
ret = restore_fbdev_mode_force(fb_helper);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
info->var.xoffset = var->xoffset;
|
info->var.xoffset = var->xoffset;
|
||||||
info->var.yoffset = var->yoffset;
|
info->var.yoffset = var->yoffset;
|
||||||
@ -1861,14 +1824,13 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
|
|||||||
struct fb_info *info)
|
struct fb_info *info)
|
||||||
{
|
{
|
||||||
struct drm_fb_helper *fb_helper = info->par;
|
struct drm_fb_helper *fb_helper = info->par;
|
||||||
|
struct drm_client_dev *client = &fb_helper->client;
|
||||||
struct drm_mode_set *modeset;
|
struct drm_mode_set *modeset;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i;
|
|
||||||
|
|
||||||
drm_modeset_lock_all(fb_helper->dev);
|
drm_modeset_lock_all(fb_helper->dev);
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
mutex_lock(&client->modeset_mutex);
|
||||||
modeset = &fb_helper->crtc_info[i].mode_set;
|
drm_client_for_each_modeset(modeset, client) {
|
||||||
|
|
||||||
modeset->x = var->xoffset;
|
modeset->x = var->xoffset;
|
||||||
modeset->y = var->yoffset;
|
modeset->y = var->yoffset;
|
||||||
|
|
||||||
@ -1880,6 +1842,7 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&client->modeset_mutex);
|
||||||
drm_modeset_unlock_all(fb_helper->dev);
|
drm_modeset_unlock_all(fb_helper->dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -1926,10 +1889,12 @@ EXPORT_SYMBOL(drm_fb_helper_pan_display);
|
|||||||
static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
||||||
int preferred_bpp)
|
int preferred_bpp)
|
||||||
{
|
{
|
||||||
|
struct drm_client_dev *client = &fb_helper->client;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int crtc_count = 0;
|
int crtc_count = 0;
|
||||||
int i;
|
int i;
|
||||||
struct drm_fb_helper_surface_size sizes;
|
struct drm_fb_helper_surface_size sizes;
|
||||||
|
struct drm_mode_set *mode_set;
|
||||||
int best_depth = 0;
|
int best_depth = 0;
|
||||||
|
|
||||||
memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
|
memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
|
||||||
@ -1980,13 +1945,13 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
|||||||
* supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth
|
* supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth
|
||||||
* 16) we need to scale down the depth of the sizes we request.
|
* 16) we need to scale down the depth of the sizes we request.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
mutex_lock(&client->modeset_mutex);
|
||||||
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
|
drm_client_for_each_modeset(mode_set, client) {
|
||||||
struct drm_crtc *crtc = mode_set->crtc;
|
struct drm_crtc *crtc = mode_set->crtc;
|
||||||
struct drm_plane *plane = crtc->primary;
|
struct drm_plane *plane = crtc->primary;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
DRM_DEBUG("test CRTC %d primary plane\n", i);
|
DRM_DEBUG("test CRTC %u primary plane\n", drm_crtc_index(crtc));
|
||||||
|
|
||||||
for (j = 0; j < plane->format_count; j++) {
|
for (j = 0; j < plane->format_count; j++) {
|
||||||
const struct drm_format_info *fmt;
|
const struct drm_format_info *fmt;
|
||||||
@ -2026,9 +1991,8 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
|||||||
|
|
||||||
/* first up get a count of crtcs now in use and new min/maxes width/heights */
|
/* first up get a count of crtcs now in use and new min/maxes width/heights */
|
||||||
crtc_count = 0;
|
crtc_count = 0;
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
drm_client_for_each_modeset(mode_set, client) {
|
||||||
struct drm_display_mode *desired_mode;
|
struct drm_display_mode *desired_mode;
|
||||||
struct drm_mode_set *mode_set;
|
|
||||||
int x, y, j;
|
int x, y, j;
|
||||||
/* in case of tile group, are we the last tile vert or horiz?
|
/* in case of tile group, are we the last tile vert or horiz?
|
||||||
* If no tile group you are always the last one both vertically
|
* If no tile group you are always the last one both vertically
|
||||||
@ -2036,7 +2000,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
|||||||
*/
|
*/
|
||||||
bool lastv = true, lasth = true;
|
bool lastv = true, lasth = true;
|
||||||
|
|
||||||
mode_set = &fb_helper->crtc_info[i].mode_set;
|
|
||||||
desired_mode = mode_set->mode;
|
desired_mode = mode_set->mode;
|
||||||
|
|
||||||
if (!desired_mode)
|
if (!desired_mode)
|
||||||
@ -2066,6 +2029,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
|||||||
if (lastv)
|
if (lastv)
|
||||||
sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
|
sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&client->modeset_mutex);
|
||||||
|
|
||||||
if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
|
if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
|
||||||
DRM_INFO("Cannot find any crtc or sizes\n");
|
DRM_INFO("Cannot find any crtc or sizes\n");
|
||||||
@ -2297,7 +2261,7 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
|
|||||||
struct drm_display_mode *dmt_mode, *mode;
|
struct drm_display_mode *dmt_mode, *mode;
|
||||||
|
|
||||||
/* only contemplate cloning in the single crtc case */
|
/* only contemplate cloning in the single crtc case */
|
||||||
if (fb_helper->crtc_count > 1)
|
if (fb_helper->dev->mode_config.num_crtc > 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
@ -2486,15 +2450,17 @@ static bool connector_has_possible_crtc(struct drm_connector *connector,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
|
static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
|
||||||
struct drm_fb_helper_crtc **best_crtcs,
|
struct drm_crtc **best_crtcs,
|
||||||
struct drm_display_mode **modes,
|
struct drm_display_mode **modes,
|
||||||
int n, int width, int height)
|
int n, int width, int height)
|
||||||
{
|
{
|
||||||
int c, o;
|
struct drm_client_dev *client = &fb_helper->client;
|
||||||
struct drm_connector *connector;
|
struct drm_connector *connector;
|
||||||
int my_score, best_score, score;
|
int my_score, best_score, score;
|
||||||
struct drm_fb_helper_crtc **crtcs, *crtc;
|
struct drm_crtc **crtcs, *crtc;
|
||||||
|
struct drm_mode_set *modeset;
|
||||||
struct drm_fb_helper_connector *fb_helper_conn;
|
struct drm_fb_helper_connector *fb_helper_conn;
|
||||||
|
int o;
|
||||||
|
|
||||||
if (n == fb_helper->connector_count)
|
if (n == fb_helper->connector_count)
|
||||||
return 0;
|
return 0;
|
||||||
@ -2507,8 +2473,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
|
|||||||
if (modes[n] == NULL)
|
if (modes[n] == NULL)
|
||||||
return best_score;
|
return best_score;
|
||||||
|
|
||||||
crtcs = kcalloc(fb_helper->connector_count,
|
crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
|
||||||
sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
|
|
||||||
if (!crtcs)
|
if (!crtcs)
|
||||||
return best_score;
|
return best_score;
|
||||||
|
|
||||||
@ -2524,11 +2489,10 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
|
|||||||
* select a crtc for this connector and then attempt to configure
|
* select a crtc for this connector and then attempt to configure
|
||||||
* remaining connectors
|
* remaining connectors
|
||||||
*/
|
*/
|
||||||
for (c = 0; c < fb_helper->crtc_count; c++) {
|
drm_client_for_each_modeset(modeset, client) {
|
||||||
crtc = &fb_helper->crtc_info[c];
|
crtc = modeset->crtc;
|
||||||
|
|
||||||
if (!connector_has_possible_crtc(connector,
|
if (!connector_has_possible_crtc(connector, crtc))
|
||||||
crtc->mode_set.crtc))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (o = 0; o < n; o++)
|
for (o = 0; o < n; o++)
|
||||||
@ -2537,7 +2501,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
|
|||||||
|
|
||||||
if (o < n) {
|
if (o < n) {
|
||||||
/* ignore cloning unless only a single crtc */
|
/* ignore cloning unless only a single crtc */
|
||||||
if (fb_helper->crtc_count > 1)
|
if (fb_helper->dev->mode_config.num_crtc > 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!drm_mode_equal(modes[o], modes[n]))
|
if (!drm_mode_equal(modes[o], modes[n]))
|
||||||
@ -2545,14 +2509,13 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
|
|||||||
}
|
}
|
||||||
|
|
||||||
crtcs[n] = crtc;
|
crtcs[n] = crtc;
|
||||||
memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
|
memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
|
||||||
score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
|
score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
|
||||||
width, height);
|
width, height);
|
||||||
if (score > best_score) {
|
if (score > best_score) {
|
||||||
best_score = score;
|
best_score = score;
|
||||||
memcpy(best_crtcs, crtcs,
|
memcpy(best_crtcs, crtcs,
|
||||||
fb_helper->connector_count *
|
fb_helper->connector_count * sizeof(*crtcs));
|
||||||
sizeof(struct drm_fb_helper_crtc *));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2560,21 +2523,9 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
|
|||||||
return best_score;
|
return best_score;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct drm_fb_helper_crtc *
|
|
||||||
drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++)
|
|
||||||
if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
|
|
||||||
return &fb_helper->crtc_info[i];
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to read the BIOS display configuration and use it for the initial config */
|
/* Try to read the BIOS display configuration and use it for the initial config */
|
||||||
static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
|
static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
|
||||||
struct drm_fb_helper_crtc **crtcs,
|
struct drm_crtc **crtcs,
|
||||||
struct drm_display_mode **modes,
|
struct drm_display_mode **modes,
|
||||||
struct drm_fb_offset *offsets,
|
struct drm_fb_offset *offsets,
|
||||||
bool *enabled, int width, int height)
|
bool *enabled, int width, int height)
|
||||||
@ -2610,7 +2561,7 @@ retry:
|
|||||||
struct drm_fb_helper_connector *fb_conn;
|
struct drm_fb_helper_connector *fb_conn;
|
||||||
struct drm_connector *connector;
|
struct drm_connector *connector;
|
||||||
struct drm_encoder *encoder;
|
struct drm_encoder *encoder;
|
||||||
struct drm_fb_helper_crtc *new_crtc;
|
struct drm_crtc *new_crtc;
|
||||||
|
|
||||||
fb_conn = fb_helper->connector_info[i];
|
fb_conn = fb_helper->connector_info[i];
|
||||||
connector = fb_conn->connector;
|
connector = fb_conn->connector;
|
||||||
@ -2652,7 +2603,7 @@ retry:
|
|||||||
|
|
||||||
num_connectors_enabled++;
|
num_connectors_enabled++;
|
||||||
|
|
||||||
new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
|
new_crtc = connector->state->crtc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure we're not trying to drive multiple connectors
|
* Make sure we're not trying to drive multiple connectors
|
||||||
@ -2752,10 +2703,11 @@ bail:
|
|||||||
static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
|
static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
|
||||||
u32 width, u32 height)
|
u32 width, u32 height)
|
||||||
{
|
{
|
||||||
|
struct drm_client_dev *client = &fb_helper->client;
|
||||||
struct drm_device *dev = fb_helper->dev;
|
struct drm_device *dev = fb_helper->dev;
|
||||||
struct drm_fb_helper_crtc **crtcs;
|
|
||||||
struct drm_display_mode **modes;
|
struct drm_display_mode **modes;
|
||||||
struct drm_fb_offset *offsets;
|
struct drm_fb_offset *offsets;
|
||||||
|
struct drm_crtc **crtcs;
|
||||||
bool *enabled;
|
bool *enabled;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -2763,8 +2715,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
|
|||||||
/* prevent concurrent modification of connector_count by hotplug */
|
/* prevent concurrent modification of connector_count by hotplug */
|
||||||
lockdep_assert_held(&fb_helper->lock);
|
lockdep_assert_held(&fb_helper->lock);
|
||||||
|
|
||||||
crtcs = kcalloc(fb_helper->connector_count,
|
crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
|
||||||
sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
|
|
||||||
modes = kcalloc(fb_helper->connector_count,
|
modes = kcalloc(fb_helper->connector_count,
|
||||||
sizeof(struct drm_display_mode *), GFP_KERNEL);
|
sizeof(struct drm_display_mode *), GFP_KERNEL);
|
||||||
offsets = kcalloc(fb_helper->connector_count,
|
offsets = kcalloc(fb_helper->connector_count,
|
||||||
@ -2776,6 +2727,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&client->modeset_mutex);
|
||||||
|
|
||||||
mutex_lock(&fb_helper->dev->mode_config.mutex);
|
mutex_lock(&fb_helper->dev->mode_config.mutex);
|
||||||
if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
|
if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
|
||||||
DRM_DEBUG_KMS("No connectors reported connected with modes\n");
|
DRM_DEBUG_KMS("No connectors reported connected with modes\n");
|
||||||
@ -2800,24 +2753,24 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
|
|||||||
}
|
}
|
||||||
mutex_unlock(&fb_helper->dev->mode_config.mutex);
|
mutex_unlock(&fb_helper->dev->mode_config.mutex);
|
||||||
|
|
||||||
/* need to set the modesets up here for use later */
|
drm_client_modeset_release(client);
|
||||||
/* fill out the connector<->crtc mappings into the modesets */
|
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++)
|
|
||||||
drm_fb_helper_modeset_release(fb_helper,
|
|
||||||
&fb_helper->crtc_info[i].mode_set);
|
|
||||||
|
|
||||||
drm_fb_helper_for_each_connector(fb_helper, i) {
|
drm_fb_helper_for_each_connector(fb_helper, i) {
|
||||||
struct drm_display_mode *mode = modes[i];
|
struct drm_display_mode *mode = modes[i];
|
||||||
struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
|
struct drm_crtc *crtc = crtcs[i];
|
||||||
struct drm_fb_offset *offset = &offsets[i];
|
struct drm_fb_offset *offset = &offsets[i];
|
||||||
|
|
||||||
if (mode && fb_crtc) {
|
if (mode && crtc) {
|
||||||
struct drm_mode_set *modeset = &fb_crtc->mode_set;
|
struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
|
||||||
struct drm_connector *connector =
|
struct drm_connector *connector =
|
||||||
fb_helper->connector_info[i]->connector;
|
fb_helper->connector_info[i]->connector;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
|
DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
|
||||||
mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
|
mode->name, crtc->base.id, offset->x, offset->y);
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
|
||||||
|
(dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1)))
|
||||||
|
break;
|
||||||
|
|
||||||
modeset->mode = drm_mode_duplicate(dev, mode);
|
modeset->mode = drm_mode_duplicate(dev, mode);
|
||||||
drm_connector_get(connector);
|
drm_connector_get(connector);
|
||||||
@ -2826,6 +2779,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
|
|||||||
modeset->y = offset->y;
|
modeset->y = offset->y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&client->modeset_mutex);
|
||||||
out:
|
out:
|
||||||
kfree(crtcs);
|
kfree(crtcs);
|
||||||
kfree(modes);
|
kfree(modes);
|
||||||
@ -2842,13 +2797,14 @@ out:
|
|||||||
*/
|
*/
|
||||||
static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
|
static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
|
||||||
{
|
{
|
||||||
|
struct drm_client_dev *client = &fb_helper->client;
|
||||||
struct fb_info *info = fb_helper->fbdev;
|
struct fb_info *info = fb_helper->fbdev;
|
||||||
unsigned int rotation, sw_rotations = 0;
|
unsigned int rotation, sw_rotations = 0;
|
||||||
|
struct drm_mode_set *modeset;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
mutex_lock(&client->modeset_mutex);
|
||||||
struct drm_mode_set *modeset = &fb_helper->crtc_info[i].mode_set;
|
drm_client_for_each_modeset(modeset, client) {
|
||||||
|
|
||||||
if (!modeset->num_connectors)
|
if (!modeset->num_connectors)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -2860,6 +2816,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
|
|||||||
else
|
else
|
||||||
sw_rotations |= rotation;
|
sw_rotations |= rotation;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&client->modeset_mutex);
|
||||||
|
|
||||||
mutex_lock(&fb_helper->dev->mode_config.mutex);
|
mutex_lock(&fb_helper->dev->mode_config.mutex);
|
||||||
drm_fb_helper_for_each_connector(fb_helper, i) {
|
drm_fb_helper_for_each_connector(fb_helper, i) {
|
||||||
@ -3075,8 +3032,7 @@ EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
|
|||||||
* @funcs: fbdev helper functions
|
* @funcs: fbdev helper functions
|
||||||
* @preferred_bpp: Preferred bits per pixel for the device.
|
* @preferred_bpp: Preferred bits per pixel for the device.
|
||||||
* @dev->mode_config.preferred_depth is used if this is zero.
|
* @dev->mode_config.preferred_depth is used if this is zero.
|
||||||
* @max_conn_count: Maximum number of connectors.
|
* @max_conn_count: Maximum number of connectors (not used)
|
||||||
* @dev->mode_config.num_connector is used if this is zero.
|
|
||||||
*
|
*
|
||||||
* This function sets up fbdev emulation and registers fbdev for access by
|
* This function sets up fbdev emulation and registers fbdev for access by
|
||||||
* userspace. If all connectors are disconnected, setup is deferred to the next
|
* userspace. If all connectors are disconnected, setup is deferred to the next
|
||||||
@ -3104,16 +3060,9 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev,
|
|||||||
if (!preferred_bpp)
|
if (!preferred_bpp)
|
||||||
preferred_bpp = 32;
|
preferred_bpp = 32;
|
||||||
|
|
||||||
if (!max_conn_count)
|
|
||||||
max_conn_count = dev->mode_config.num_connector;
|
|
||||||
if (!max_conn_count) {
|
|
||||||
DRM_DEV_ERROR(dev->dev, "fbdev: No connectors\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
drm_fb_helper_prepare(dev, fb_helper, funcs);
|
drm_fb_helper_prepare(dev, fb_helper, funcs);
|
||||||
|
|
||||||
ret = drm_fb_helper_init(dev, fb_helper, max_conn_count);
|
ret = drm_fb_helper_init(dev, fb_helper, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
DRM_DEV_ERROR(dev->dev, "fbdev: Failed to initialize (ret=%d)\n", ret);
|
DRM_DEV_ERROR(dev->dev, "fbdev: Failed to initialize (ret=%d)\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
@ -3426,7 +3375,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
|
|||||||
|
|
||||||
drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
|
drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
|
||||||
|
|
||||||
ret = drm_fb_helper_init(dev, fb_helper, dev->mode_config.num_connector);
|
ret = drm_fb_helper_init(dev, fb_helper, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -3,8 +3,12 @@
|
|||||||
#ifndef _DRM_CLIENT_H_
|
#ifndef _DRM_CLIENT_H_
|
||||||
#define _DRM_CLIENT_H_
|
#define _DRM_CLIENT_H_
|
||||||
|
|
||||||
|
#include <linux/lockdep.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#include <drm/drm_crtc.h>
|
||||||
|
|
||||||
struct drm_client_dev;
|
struct drm_client_dev;
|
||||||
struct drm_device;
|
struct drm_device;
|
||||||
struct drm_file;
|
struct drm_file;
|
||||||
@ -13,6 +17,8 @@ struct drm_gem_object;
|
|||||||
struct drm_minor;
|
struct drm_minor;
|
||||||
struct module;
|
struct module;
|
||||||
|
|
||||||
|
#define DRM_CLIENT_MAX_CLONED_CONNECTORS 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct drm_client_funcs - DRM client callbacks
|
* struct drm_client_funcs - DRM client callbacks
|
||||||
*/
|
*/
|
||||||
@ -85,6 +91,16 @@ struct drm_client_dev {
|
|||||||
* @file: DRM file
|
* @file: DRM file
|
||||||
*/
|
*/
|
||||||
struct drm_file *file;
|
struct drm_file *file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @modeset_mutex: Protects @modesets.
|
||||||
|
*/
|
||||||
|
struct mutex modeset_mutex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @modesets: CRTC configurations
|
||||||
|
*/
|
||||||
|
struct drm_mode_set *modesets;
|
||||||
};
|
};
|
||||||
|
|
||||||
int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
|
int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
|
||||||
@ -135,6 +151,20 @@ struct drm_client_buffer *
|
|||||||
drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format);
|
drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format);
|
||||||
void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
|
void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
|
||||||
|
|
||||||
|
int drm_client_modeset_create(struct drm_client_dev *client);
|
||||||
|
void drm_client_modeset_free(struct drm_client_dev *client);
|
||||||
|
void drm_client_modeset_release(struct drm_client_dev *client);
|
||||||
|
struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_client_for_each_modeset() - Iterate over client modesets
|
||||||
|
* @modeset: &drm_mode_set loop cursor
|
||||||
|
* @client: DRM client
|
||||||
|
*/
|
||||||
|
#define drm_client_for_each_modeset(modeset, client) \
|
||||||
|
for (({ lockdep_assert_held(&(client)->modeset_mutex); }), \
|
||||||
|
modeset = (client)->modesets; modeset->crtc; modeset++)
|
||||||
|
|
||||||
int drm_client_debugfs_init(struct drm_minor *minor);
|
int drm_client_debugfs_init(struct drm_minor *minor);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -47,10 +47,6 @@ struct drm_fb_offset {
|
|||||||
int x, y;
|
int x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drm_fb_helper_crtc {
|
|
||||||
struct drm_mode_set mode_set;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
|
* struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
|
||||||
* @fb_width: fbdev width
|
* @fb_width: fbdev width
|
||||||
@ -109,8 +105,6 @@ struct drm_fb_helper_connector {
|
|||||||
* struct drm_fb_helper - main structure to emulate fbdev on top of KMS
|
* struct drm_fb_helper - main structure to emulate fbdev on top of KMS
|
||||||
* @fb: Scanout framebuffer object
|
* @fb: Scanout framebuffer object
|
||||||
* @dev: DRM device
|
* @dev: DRM device
|
||||||
* @crtc_count: number of possible CRTCs
|
|
||||||
* @crtc_info: per-CRTC helper state (mode, x/y offset, etc)
|
|
||||||
* @connector_count: number of connected connectors
|
* @connector_count: number of connected connectors
|
||||||
* @connector_info_alloc_count: size of connector_info
|
* @connector_info_alloc_count: size of connector_info
|
||||||
* @funcs: driver callbacks for fb helper
|
* @funcs: driver callbacks for fb helper
|
||||||
@ -144,8 +138,6 @@ struct drm_fb_helper {
|
|||||||
|
|
||||||
struct drm_framebuffer *fb;
|
struct drm_framebuffer *fb;
|
||||||
struct drm_device *dev;
|
struct drm_device *dev;
|
||||||
int crtc_count;
|
|
||||||
struct drm_fb_helper_crtc *crtc_info;
|
|
||||||
int connector_count;
|
int connector_count;
|
||||||
int connector_info_alloc_count;
|
int connector_info_alloc_count;
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user