summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_fb_helper.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-03-30 05:34:15 +0000
committerDave Airlie <airlied@redhat.com>2010-04-07 10:28:01 +1000
commit0b4c0f3f0eceacb691e2b5570d9b16d751ce1b48 (patch)
tree708eecc3e3b86f4328df588400e2b7a3f6f2b32d /drivers/gpu/drm/drm_fb_helper.c
parent8be48d924c307e72e3797ab5bde81b07a1ccc52d (diff)
drm/kms/fb: separate fbdev connector list from core drm connectors
This breaks the connection between the core drm connector list and the fbdev connector usage, and allows them to become disjoint in the future. It also removes the untype void* that was in the connector struct to support this. All connectors are added to the fbdev now but this could be changed in the future. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_fb_helper.c')
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c196
1 files changed, 103 insertions, 93 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 2515563063ce..9808f6e37a9d 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -41,15 +41,33 @@ MODULE_LICENSE("GPL and additional rights");
static LIST_HEAD(kernel_fb_helper_list);
-int drm_fb_helper_add_connector(struct drm_connector *connector)
+/* simple single crtc case helper function */
+int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
{
- connector->fb_helper_private = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
- if (!connector->fb_helper_private)
- return -ENOMEM;
+ struct drm_device *dev = fb_helper->dev;
+ struct drm_connector *connector;
+ int i;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ struct drm_fb_helper_connector *fb_helper_connector;
+
+ fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
+ if (!fb_helper_connector)
+ goto fail;
+ fb_helper_connector->connector = connector;
+ fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
+ }
return 0;
+fail:
+ for (i = 0; i < fb_helper->connector_count; i++) {
+ kfree(fb_helper->connector_info[i]);
+ fb_helper->connector_info[i] = NULL;
+ }
+ fb_helper->connector_count = 0;
+ return -ENOMEM;
}
-EXPORT_SYMBOL(drm_fb_helper_add_connector);
+EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
/**
* drm_fb_helper_connector_parse_command_line - parse command line for connector
@@ -64,7 +82,7 @@ EXPORT_SYMBOL(drm_fb_helper_add_connector);
*
* enable/enable Digital/disable bit at the end
*/
-static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *connector,
+static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
const char *mode_option)
{
const char *name;
@@ -74,13 +92,13 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
int i;
enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
- struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
struct drm_fb_helper_cmdline_mode *cmdline_mode;
+ struct drm_connector *connector = fb_helper_conn->connector;
- if (!fb_help_conn)
+ if (!fb_helper_conn)
return false;
- cmdline_mode = &fb_help_conn->cmdline_mode;
+ cmdline_mode = &fb_helper_conn->cmdline_mode;
if (!mode_option)
mode_option = fb_mode_option;
@@ -203,18 +221,21 @@ done:
return true;
}
-int drm_fb_helper_parse_command_line(struct drm_device *dev)
+static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
{
- struct drm_connector *connector;
+ struct drm_fb_helper_connector *fb_helper_conn;
+ int i;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ for (i = 0; i < fb_helper->connector_count; i++) {
char *option = NULL;
+ fb_helper_conn = fb_helper->connector_info[i];
+
/* do something on return - turn off connector maybe */
- if (fb_get_options(drm_get_connector_name(connector), &option))
+ if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
continue;
- drm_fb_helper_connector_parse_command_line(connector, option);
+ drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
}
return 0;
}
@@ -391,6 +412,9 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
{
int i;
+ for (i = 0; i < helper->connector_count; i++)
+ kfree(helper->connector_info[i]);
+ kfree(helper->connector_info);
for (i = 0; i < helper->crtc_count; i++)
kfree(helper->crtc_info[i].mode_set.connectors);
kfree(helper->crtc_info);
@@ -411,6 +435,13 @@ int drm_fb_helper_init_crtc_count(struct drm_device *dev,
return -ENOMEM;
helper->crtc_count = crtc_count;
+ helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
+ if (!helper->connector_info) {
+ kfree(helper->crtc_info);
+ return -ENOMEM;
+ }
+ helper->connector_count = 0;
+
for (i = 0; i < crtc_count; i++) {
helper->crtc_info[i].mode_set.connectors =
kcalloc(max_conn_count,
@@ -672,14 +703,10 @@ int drm_fb_helper_set_par(struct fb_info *info)
mutex_lock(&dev->mode_config.mutex);
for (i = 0; i < fb_helper->crtc_count; i++) {
crtc = fb_helper->crtc_info[i].mode_set.crtc;
-
- if (crtc->fb != fb_helper->crtc_info[i].mode_set.fb) {
- ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
-
- if (ret) {
- mutex_unlock(&dev->mode_config.mutex);
- return ret;
- }
+ ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
+ if (ret) {
+ mutex_unlock(&dev->mode_config.mutex);
+ return ret;
}
}
mutex_unlock(&dev->mode_config.mutex);
@@ -722,8 +749,6 @@ EXPORT_SYMBOL(drm_fb_helper_pan_display);
int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
int preferred_bpp)
{
- struct drm_device *dev = fb_helper->dev;
- struct drm_connector *connector;
int new_fb = 0;
int crtc_count = 0;
int ret, i;
@@ -743,14 +768,11 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
}
/* first up get a count of crtcs now in use and new min/maxes width/heights */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
+ for (i = 0; i < fb_helper->connector_count; i++) {
+ struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
struct drm_fb_helper_cmdline_mode *cmdline_mode;
- if (!fb_help_conn)
- continue;
-
- cmdline_mode = &fb_help_conn->cmdline_mode;
+ cmdline_mode = &fb_helper_conn->cmdline_mode;
if (cmdline_mode->bpp_specified) {
switch (cmdline_mode->bpp) {
@@ -954,24 +976,27 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
}
EXPORT_SYMBOL(drm_fb_helper_fill_var);
-static int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
- uint32_t maxY)
+static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
+ uint32_t maxX,
+ uint32_t maxY)
{
struct drm_connector *connector;
int count = 0;
+ int i;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ for (i = 0; i < fb_helper->connector_count; i++) {
+ connector = fb_helper->connector_info[i]->connector;
count += connector->funcs->fill_modes(connector, maxX, maxY);
}
return count;
}
-static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height)
+static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
{
struct drm_display_mode *mode;
- list_for_each_entry(mode, &connector->modes, head) {
+ list_for_each_entry(mode, &fb_connector->connector->modes, head) {
if (drm_mode_width(mode) > width ||
drm_mode_height(mode) > height)
continue;
@@ -981,28 +1006,20 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *con
return NULL;
}
-static bool drm_has_cmdline_mode(struct drm_connector *connector)
+static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
{
- struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
struct drm_fb_helper_cmdline_mode *cmdline_mode;
-
- if (!fb_help_conn)
- return false;
-
- cmdline_mode = &fb_help_conn->cmdline_mode;
+ cmdline_mode = &fb_connector->cmdline_mode;
return cmdline_mode->specified;
}
-static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height)
+static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
+ int width, int height)
{
- struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
struct drm_fb_helper_cmdline_mode *cmdline_mode;
struct drm_display_mode *mode = NULL;
- if (!fb_help_conn)
- return mode;
-
- cmdline_mode = &fb_help_conn->cmdline_mode;
+ cmdline_mode = &fb_helper_conn->cmdline_mode;
if (cmdline_mode->specified == false)
return mode;
@@ -1012,7 +1029,7 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *conn
if (cmdline_mode->rb || cmdline_mode->margins)
goto create_mode;
- list_for_each_entry(mode, &connector->modes, head) {
+ list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
/* check width/height */
if (mode->hdisplay != cmdline_mode->xres ||
mode->vdisplay != cmdline_mode->yres)
@@ -1031,13 +1048,13 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *conn
}
create_mode:
- mode = drm_cvt_mode(connector->dev, cmdline_mode->xres,
+ mode = drm_cvt_mode(fb_helper_conn->connector->dev, cmdline_mode->xres,
cmdline_mode->yres,
cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
cmdline_mode->rb, cmdline_mode->interlace,
cmdline_mode->margins);
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
- list_add(&mode->head, &connector->modes);
+ list_add(&mode->head, &fb_helper_conn->connector->modes);
return mode;
}
@@ -1053,62 +1070,60 @@ static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
return enable;
}
-static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
+static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
+ bool *enabled)
{
bool any_enabled = false;
struct drm_connector *connector;
int i = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ for (i = 0; i < fb_helper->connector_count; i++) {
+ connector = fb_helper->connector_info[i]->connector;
enabled[i] = drm_connector_enabled(connector, true);
DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
enabled[i] ? "yes" : "no");
any_enabled |= enabled[i];
- i++;
}
if (any_enabled)
return;
- i = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ for (i = 0; i < fb_helper->connector_count; i++) {
+ connector = fb_helper->connector_info[i]->connector;
enabled[i] = drm_connector_enabled(connector, false);
- i++;
}
}
-static bool drm_target_preferred(struct drm_device *dev,
+static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
struct drm_display_mode **modes,
bool *enabled, int width, int height)
{
- struct drm_connector *connector;
- int i = 0;
+ struct drm_fb_helper_connector *fb_helper_conn;
+ int i;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ for (i = 0; i < fb_helper->connector_count; i++) {
+ fb_helper_conn = fb_helper->connector_info[i];
- if (enabled[i] == false) {
- i++;
+ if (enabled[i] == false)
continue;
- }
DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
- connector->base.id);
+ fb_helper_conn->connector->base.id);
/* got for command line mode first */
- modes[i] = drm_pick_cmdline_mode(connector, width, height);
+ modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
if (!modes[i]) {
DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
- connector->base.id);
- modes[i] = drm_has_preferred_mode(connector, width, height);
+ fb_helper_conn->connector->base.id);
+ modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
}
/* No preferred modes, pick one off the list */
- if (!modes[i] && !list_empty(&connector->modes)) {
- list_for_each_entry(modes[i], &connector->modes, head)
+ if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
+ list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
break;
}
DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
"none");
- i++;
}
return true;
}
@@ -1126,15 +1141,13 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_crtc *best_crtc;
int my_score, best_score, score;
struct drm_fb_helper_crtc **crtcs, *crtc;
+ struct drm_fb_helper_connector *fb_helper_conn;
- if (n == fb_helper->dev->mode_config.num_connector)
+ if (n == fb_helper->connector_count)
return 0;
- c = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (c == n)
- break;
- c++;
- }
+
+ fb_helper_conn = fb_helper->connector_info[n];
+ connector = fb_helper_conn->connector;
best_crtcs[n] = NULL;
best_crtc = NULL;
@@ -1150,9 +1163,9 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
my_score = 1;
if (connector->status == connector_status_connected)
my_score++;
- if (drm_has_cmdline_mode(connector))
+ if (drm_has_cmdline_mode(fb_helper_conn))
my_score++;
- if (drm_has_preferred_mode(connector, width, height))
+ if (drm_has_preferred_mode(fb_helper_conn, width, height))
my_score++;
connector_funcs = connector->helper_private;
@@ -1201,7 +1214,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
struct drm_fb_helper_crtc **crtcs;
struct drm_display_mode **modes;
struct drm_encoder *encoder;
- struct drm_connector *connector;
struct drm_mode_set *modeset;
bool *enabled;
int width, height;
@@ -1224,9 +1236,9 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
enabled = kcalloc(dev->mode_config.num_connector,
sizeof(bool), GFP_KERNEL);
- drm_enable_connectors(dev, enabled);
+ drm_enable_connectors(fb_helper, enabled);
- ret = drm_target_preferred(dev, modes, enabled, width, height);
+ ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
if (!ret)
DRM_ERROR("Unable to find initial modes\n");
@@ -1241,8 +1253,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
modeset->num_connectors = 0;
}
- i = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ for (i = 0; i < fb_helper->connector_count; i++) {
struct drm_display_mode *mode = modes[i];
struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
modeset = &fb_crtc->mode_set;
@@ -1255,9 +1266,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
drm_mode_destroy(dev, modeset->mode);
modeset->mode = drm_mode_duplicate(dev,
fb_crtc->desired_mode);
- modeset->connectors[modeset->num_connectors++] = connector;
+ modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
}
- i++;
}
kfree(crtcs);
@@ -1287,11 +1297,11 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper)
/* 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->dev);
+ drm_fb_helper_parse_command_line(fb_helper);
- count = drm_helper_probe_connector_modes(dev,
- dev->mode_config.max_width,
- dev->mode_config.max_height);
+ count = drm_fb_helper_probe_connector_modes(fb_helper,
+ dev->mode_config.max_width,
+ dev->mode_config.max_height);
/*
* we shouldn't end up with no modes here.
@@ -1310,8 +1320,8 @@ bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper,
{
DRM_DEBUG_KMS("\n");
- drm_helper_probe_connector_modes(fb_helper->dev, max_width,
- max_height);
+ drm_fb_helper_probe_connector_modes(fb_helper, max_width,
+ max_height);
drm_setup_crtcs(fb_helper);