aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_crtc.c1
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c79
-rw-r--r--drivers/gpu/drm/drm_edid.c6
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c224
-rw-r--r--drivers/gpu/drm/drm_modes.c3
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c25
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c26
-rw-r--r--include/drm/drm_crtc.h14
-rw-r--r--include/drm/drm_fb_helper.h24
10 files changed, 386 insertions, 21 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index ba728ad77f2a..8e7b0ebece0c 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -482,6 +482,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
482 list_for_each_entry_safe(mode, t, &connector->user_modes, head) 482 list_for_each_entry_safe(mode, t, &connector->user_modes, head)
483 drm_mode_remove(connector, mode); 483 drm_mode_remove(connector, mode);
484 484
485 kfree(connector->fb_helper_private);
485 mutex_lock(&dev->mode_config.mutex); 486 mutex_lock(&dev->mode_config.mutex);
486 drm_mode_object_put(dev, &connector->base); 487 drm_mode_object_put(dev, &connector->base);
487 list_del(&connector->head); 488 list_del(&connector->head);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index fe8697447f32..82fd6e82450f 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -32,6 +32,7 @@
32#include "drmP.h" 32#include "drmP.h"
33#include "drm_crtc.h" 33#include "drm_crtc.h"
34#include "drm_crtc_helper.h" 34#include "drm_crtc_helper.h"
35#include "drm_fb_helper.h"
35 36
36static void drm_mode_validate_flag(struct drm_connector *connector, 37static void drm_mode_validate_flag(struct drm_connector *connector,
37 int flags) 38 int flags)
@@ -90,7 +91,15 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
90 list_for_each_entry_safe(mode, t, &connector->modes, head) 91 list_for_each_entry_safe(mode, t, &connector->modes, head)
91 mode->status = MODE_UNVERIFIED; 92 mode->status = MODE_UNVERIFIED;
92 93
93 connector->status = connector->funcs->detect(connector); 94 if (connector->force) {
95 if (connector->force == DRM_FORCE_ON)
96 connector->status = connector_status_connected;
97 else
98 connector->status = connector_status_disconnected;
99 if (connector->funcs->force)
100 connector->funcs->force(connector);
101 } else
102 connector->status = connector->funcs->detect(connector);
94 103
95 if (connector->status == connector_status_disconnected) { 104 if (connector->status == connector_status_disconnected) {
96 DRM_DEBUG_KMS("%s is disconnected\n", 105 DRM_DEBUG_KMS("%s is disconnected\n",
@@ -267,6 +276,56 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *con
267 return NULL; 276 return NULL;
268} 277}
269 278
279static bool drm_has_cmdline_mode(struct drm_connector *connector)
280{
281 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
282 struct drm_fb_helper_cmdline_mode *cmdline_mode = &fb_help_conn->cmdline_mode;
283 return cmdline_mode->specified;
284}
285
286static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height)
287{
288 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
289 struct drm_fb_helper_cmdline_mode *cmdline_mode = &fb_help_conn->cmdline_mode;
290 struct drm_display_mode *mode = NULL;
291
292 if (cmdline_mode->specified == false)
293 return mode;
294
295 /* attempt to find a matching mode in the list of modes
296 * we have gotten so far, if not add a CVT mode that conforms
297 */
298 if (cmdline_mode->rb || cmdline_mode->margins)
299 goto create_mode;
300
301 list_for_each_entry(mode, &connector->modes, head) {
302 /* check width/height */
303 if (mode->hdisplay != cmdline_mode->xres ||
304 mode->vdisplay != cmdline_mode->yres)
305 continue;
306
307 if (cmdline_mode->refresh_specified) {
308 if (mode->vrefresh != cmdline_mode->refresh)
309 continue;
310 }
311
312 if (cmdline_mode->interlace) {
313 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
314 continue;
315 }
316 return mode;
317 }
318
319create_mode:
320 mode = drm_cvt_mode(connector->dev, cmdline_mode->xres,
321 cmdline_mode->yres,
322 cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
323 cmdline_mode->rb, cmdline_mode->interlace,
324 cmdline_mode->margins);
325 list_add(&mode->head, &connector->modes);
326 return mode;
327}
328
270static bool drm_connector_enabled(struct drm_connector *connector, bool strict) 329static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
271{ 330{
272 bool enable; 331 bool enable;
@@ -317,10 +376,16 @@ static bool drm_target_preferred(struct drm_device *dev,
317 continue; 376 continue;
318 } 377 }
319 378
320 DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", 379 DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
321 connector->base.id); 380 connector->base.id);
322 381
323 modes[i] = drm_has_preferred_mode(connector, width, height); 382 /* got for command line mode first */
383 modes[i] = drm_pick_cmdline_mode(connector, width, height);
384 if (!modes[i]) {
385 DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
386 connector->base.id);
387 modes[i] = drm_has_preferred_mode(connector, width, height);
388 }
324 /* No preferred modes, pick one off the list */ 389 /* No preferred modes, pick one off the list */
325 if (!modes[i] && !list_empty(&connector->modes)) { 390 if (!modes[i] && !list_empty(&connector->modes)) {
326 list_for_each_entry(modes[i], &connector->modes, head) 391 list_for_each_entry(modes[i], &connector->modes, head)
@@ -369,6 +434,8 @@ static int drm_pick_crtcs(struct drm_device *dev,
369 my_score = 1; 434 my_score = 1;
370 if (connector->status == connector_status_connected) 435 if (connector->status == connector_status_connected)
371 my_score++; 436 my_score++;
437 if (drm_has_cmdline_mode(connector))
438 my_score++;
372 if (drm_has_preferred_mode(connector, width, height)) 439 if (drm_has_preferred_mode(connector, width, height))
373 my_score++; 440 my_score++;
374 441
@@ -943,6 +1010,8 @@ bool drm_helper_initial_config(struct drm_device *dev)
943{ 1010{
944 int count = 0; 1011 int count = 0;
945 1012
1013 drm_fb_helper_parse_command_line(dev);
1014
946 count = drm_helper_probe_connector_modes(dev, 1015 count = drm_helper_probe_connector_modes(dev,
947 dev->mode_config.max_width, 1016 dev->mode_config.max_width,
948 dev->mode_config.max_height); 1017 dev->mode_config.max_height);
@@ -950,7 +1019,7 @@ bool drm_helper_initial_config(struct drm_device *dev)
950 /* 1019 /*
951 * we shouldn't end up with no modes here. 1020 * we shouldn't end up with no modes here.
952 */ 1021 */
953 WARN(!count, "Connected connector with 0 modes\n"); 1022 WARN(!count, "No connectors reported connected with modes\n");
954 1023
955 drm_setup_crtcs(dev); 1024 drm_setup_crtcs(dev);
956 1025
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 9888c2076b2e..3c0d2b3aed76 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -560,7 +560,8 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
560 vsize = (hsize * 9) / 16; 560 vsize = (hsize * 9) / 16;
561 /* HDTV hack */ 561 /* HDTV hack */
562 if (hsize == 1360 && vsize == 765 && vrefresh_rate == 60) { 562 if (hsize == 1360 && vsize == 765 && vrefresh_rate == 60) {
563 mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); 563 mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
564 false);
564 mode->hdisplay = 1366; 565 mode->hdisplay = 1366;
565 mode->vsync_start = mode->vsync_start - 1; 566 mode->vsync_start = mode->vsync_start - 1;
566 mode->vsync_end = mode->vsync_end - 1; 567 mode->vsync_end = mode->vsync_end - 1;
@@ -579,7 +580,8 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
579 mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); 580 mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
580 break; 581 break;
581 case LEVEL_CVT: 582 case LEVEL_CVT:
582 mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); 583 mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
584 false);
583 break; 585 break;
584 } 586 }
585 return mode; 587 return mode;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 2c4671314884..2537d2e81849 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -40,6 +40,196 @@ MODULE_LICENSE("GPL and additional rights");
40 40
41static LIST_HEAD(kernel_fb_helper_list); 41static LIST_HEAD(kernel_fb_helper_list);
42 42
43int drm_fb_helper_add_connector(struct drm_connector *connector)
44{
45 connector->fb_helper_private = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
46 if (!connector->fb_helper_private)
47 return -ENOMEM;
48
49 return 0;
50
51}
52EXPORT_SYMBOL(drm_fb_helper_add_connector);
53
54static int my_atoi(const char *name)
55{
56 int val = 0;
57
58 for (;; name++) {
59 switch (*name) {
60 case '0' ... '9':
61 val = 10*val+(*name-'0');
62 break;
63 default:
64 return val;
65 }
66 }
67}
68
69/**
70 * drm_fb_helper_connector_parse_command_line - parse command line for connector
71 * @connector - connector to parse line for
72 * @mode_option - per connector mode option
73 *
74 * This parses the connector specific then generic command lines for
75 * modes and options to configure the connector.
76 *
77 * This uses the same parameters as the fb modedb.c, except for extra
78 * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
79 *
80 * enable/enable Digital/disable bit at the end
81 */
82static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *connector,
83 const char *mode_option)
84{
85 const char *name;
86 unsigned int namelen;
87 int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
88 unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
89 int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
90 int i;
91 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
92 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
93 struct drm_fb_helper_cmdline_mode *cmdline_mode = &fb_help_conn->cmdline_mode;
94
95 if (!mode_option)
96 mode_option = fb_mode_option;
97
98 if (!mode_option) {
99 cmdline_mode->specified = false;
100 return false;
101 }
102
103 name = mode_option;
104 namelen = strlen(name);
105 for (i = namelen-1; i >= 0; i--) {
106 switch (name[i]) {
107 case '@':
108 namelen = i;
109 if (!refresh_specified && !bpp_specified &&
110 !yres_specified) {
111 refresh = my_atoi(&name[i+1]);
112 refresh_specified = 1;
113 if (cvt || rb)
114 cvt = 0;
115 } else
116 goto done;
117 break;
118 case '-':
119 namelen = i;
120 if (!bpp_specified && !yres_specified) {
121 bpp = my_atoi(&name[i+1]);
122 bpp_specified = 1;
123 if (cvt || rb)
124 cvt = 0;
125 } else
126 goto done;
127 break;
128 case 'x':
129 if (!yres_specified) {
130 yres = my_atoi(&name[i+1]);
131 yres_specified = 1;
132 } else
133 goto done;
134 case '0' ... '9':
135 break;
136 case 'M':
137 if (!yres_specified)
138 cvt = 1;
139 break;
140 case 'R':
141 if (!cvt)
142 rb = 1;
143 break;
144 case 'm':
145 if (!cvt)
146 margins = 1;
147 break;
148 case 'i':
149 if (!cvt)
150 interlace = 1;
151 break;
152 case 'e':
153 force = DRM_FORCE_ON;
154 break;
155 case 'D':
156 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) ||
157 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
158 force = DRM_FORCE_ON;
159 else
160 force = DRM_FORCE_ON_DIGITAL;
161 break;
162 case 'd':
163 force = DRM_FORCE_OFF;
164 break;
165 default:
166 goto done;
167 }
168 }
169 if (i < 0 && yres_specified) {
170 xres = my_atoi(name);
171 res_specified = 1;
172 }
173done:
174
175 DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
176 drm_get_connector_name(connector), xres, yres,
177 (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
178 "", (margins) ? " with margins" : "", (interlace) ?
179 " interlaced" : "");
180
181 if (force) {
182 const char *s;
183 switch (force) {
184 case DRM_FORCE_OFF: s = "OFF"; break;
185 case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
186 default:
187 case DRM_FORCE_ON: s = "ON"; break;
188 }
189
190 DRM_INFO("forcing %s connector %s\n",
191 drm_get_connector_name(connector), s);
192 connector->force = force;
193 }
194
195 if (res_specified) {
196 cmdline_mode->specified = true;
197 cmdline_mode->xres = xres;
198 cmdline_mode->yres = yres;
199 }
200
201 if (refresh_specified) {
202 cmdline_mode->refresh_specified = true;
203 cmdline_mode->refresh = refresh;
204 }
205
206 if (bpp_specified) {
207 cmdline_mode->bpp_specified = true;
208 cmdline_mode->bpp = bpp;
209 }
210 cmdline_mode->rb = rb ? true : false;
211 cmdline_mode->cvt = cvt ? true : false;
212 cmdline_mode->interlace = interlace ? true : false;
213
214 return true;
215}
216
217int drm_fb_helper_parse_command_line(struct drm_device *dev)
218{
219 struct drm_connector *connector;
220
221 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
222 char *option = NULL;
223
224 /* do something on return - turn off connector maybe */
225 if (fb_get_options(drm_get_connector_name(connector), &option))
226 continue;
227
228 drm_fb_helper_connector_parse_command_line(connector, option);
229 }
230 return 0;
231}
232
43bool drm_fb_helper_force_kernel_mode(void) 233bool drm_fb_helper_force_kernel_mode(void)
44{ 234{
45 int i = 0; 235 int i = 0;
@@ -484,6 +674,8 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
484 uint32_t fb_height, 674 uint32_t fb_height,
485 uint32_t surface_width, 675 uint32_t surface_width,
486 uint32_t surface_height, 676 uint32_t surface_height,
677 uint32_t surface_depth,
678 uint32_t surface_bpp,
487 struct drm_framebuffer **fb_ptr)) 679 struct drm_framebuffer **fb_ptr))
488{ 680{
489 struct drm_crtc *crtc; 681 struct drm_crtc *crtc;
@@ -497,8 +689,37 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
497 struct drm_framebuffer *fb; 689 struct drm_framebuffer *fb;
498 struct drm_mode_set *modeset = NULL; 690 struct drm_mode_set *modeset = NULL;
499 struct drm_fb_helper *fb_helper; 691 struct drm_fb_helper *fb_helper;
692 uint32_t surface_depth = 24, surface_bpp = 32;
500 693
501 /* first up get a count of crtcs now in use and new min/maxes width/heights */ 694 /* first up get a count of crtcs now in use and new min/maxes width/heights */
695 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
696 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
697 struct drm_fb_helper_cmdline_mode *cmdline_mode = &fb_help_conn->cmdline_mode;
698
699 if (cmdline_mode->bpp_specified) {
700 switch (cmdline_mode->bpp) {
701 case 8:
702 surface_depth = surface_bpp = 8;
703 break;
704 case 15:
705 surface_depth = 15;
706 surface_bpp = 16;
707 break;
708 case 16:
709 surface_depth = surface_bpp = 16;
710 break;
711 case 24:
712 surface_depth = surface_bpp = 24;
713 break;
714 case 32:
715 surface_depth = 24;
716 surface_bpp = 32;
717 break;
718 }
719 break;
720 }
721 }
722
502 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 723 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
503 if (drm_helper_crtc_in_use(crtc)) { 724 if (drm_helper_crtc_in_use(crtc)) {
504 if (crtc->desired_mode) { 725 if (crtc->desired_mode) {
@@ -527,7 +748,8 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
527 /* do we have an fb already? */ 748 /* do we have an fb already? */
528 if (list_empty(&dev->mode_config.fb_kernel_list)) { 749 if (list_empty(&dev->mode_config.fb_kernel_list)) {
529 ret = (*fb_create)(dev, fb_width, fb_height, surface_width, 750 ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
530 surface_height, &fb); 751 surface_height, surface_depth, surface_bpp,
752 &fb);
531 if (ret) 753 if (ret)
532 return -EINVAL; 754 return -EINVAL;
533 new_fb = 1; 755 new_fb = 1;
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 49404ce1666e..51f677215f1d 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -88,7 +88,7 @@ EXPORT_SYMBOL(drm_mode_debug_printmodeline);
88#define HV_FACTOR 1000 88#define HV_FACTOR 1000
89struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, 89struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
90 int vdisplay, int vrefresh, 90 int vdisplay, int vrefresh,
91 bool reduced, bool interlaced) 91 bool reduced, bool interlaced, bool margins)
92{ 92{
93 /* 1) top/bottom margin size (% of height) - default: 1.8, */ 93 /* 1) top/bottom margin size (% of height) - default: 1.8, */
94#define CVT_MARGIN_PERCENTAGE 18 94#define CVT_MARGIN_PERCENTAGE 18
@@ -101,7 +101,6 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
101 /* Pixel Clock step (kHz) */ 101 /* Pixel Clock step (kHz) */
102#define CVT_CLOCK_STEP 250 102#define CVT_CLOCK_STEP 250
103 struct drm_display_mode *drm_mode; 103 struct drm_display_mode *drm_mode;
104 bool margins = false;
105 unsigned int vfieldrate, hperiod; 104 unsigned int vfieldrate, hperiod;
106 int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync; 105 int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
107 int interlace; 106 int interlace;
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 7ba4a232a97f..e85d7e9eed7d 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -110,6 +110,7 @@ EXPORT_SYMBOL(intelfb_resize);
110static int intelfb_create(struct drm_device *dev, uint32_t fb_width, 110static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
111 uint32_t fb_height, uint32_t surface_width, 111 uint32_t fb_height, uint32_t surface_width,
112 uint32_t surface_height, 112 uint32_t surface_height,
113 uint32_t surface_depth, uint32_t surface_bpp,
113 struct drm_framebuffer **fb_p) 114 struct drm_framebuffer **fb_p)
114{ 115{
115 struct fb_info *info; 116 struct fb_info *info;
@@ -125,9 +126,9 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
125 mode_cmd.width = surface_width; 126 mode_cmd.width = surface_width;
126 mode_cmd.height = surface_height; 127 mode_cmd.height = surface_height;
127 128
128 mode_cmd.bpp = 32; 129 mode_cmd.bpp = surface_bpp;
129 mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); 130 mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64);
130 mode_cmd.depth = 24; 131 mode_cmd.depth = surface_depth;
131 132
132 size = mode_cmd.pitch * mode_cmd.height; 133 size = mode_cmd.pitch * mode_cmd.height;
133 size = ALIGN(size, PAGE_SIZE); 134 size = ALIGN(size, PAGE_SIZE);
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index f8cb8b4e2b17..db155d5e60ce 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -26,6 +26,7 @@
26#include "drmP.h" 26#include "drmP.h"
27#include "drm_edid.h" 27#include "drm_edid.h"
28#include "drm_crtc_helper.h" 28#include "drm_crtc_helper.h"
29#include "drm_fb_helper.h"
29#include "radeon_drm.h" 30#include "radeon_drm.h"
30#include "radeon.h" 31#include "radeon.h"
31#include "atom.h" 32#include "atom.h"
@@ -245,7 +246,7 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn
245 if (common_modes[i].w < 320 || common_modes[i].h < 200) 246 if (common_modes[i].w < 320 || common_modes[i].h < 200)
246 continue; 247 continue;
247 248
248 mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false); 249 mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
249 drm_mode_probed_add(connector, mode); 250 drm_mode_probed_add(connector, mode);
250 } 251 }
251} 252}
@@ -559,7 +560,7 @@ static int radeon_tv_get_modes(struct drm_connector *connector)
559 radeon_add_common_modes(encoder, connector); 560 radeon_add_common_modes(encoder, connector);
560 else { 561 else {
561 /* only 800x600 is supported right now on pre-avivo chips */ 562 /* only 800x600 is supported right now on pre-avivo chips */
562 tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false); 563 tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false, false);
563 tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 564 tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
564 drm_mode_probed_add(connector, tv_mode); 565 drm_mode_probed_add(connector, tv_mode);
565 } 566 }
@@ -743,6 +744,15 @@ struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
743 return NULL; 744 return NULL;
744} 745}
745 746
747static void radeon_dvi_force(struct drm_connector *connector)
748{
749 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
750 if (connector->force == DRM_FORCE_ON)
751 radeon_connector->use_digital = false;
752 if (connector->force == DRM_FORCE_ON_DIGITAL)
753 radeon_connector->use_digital = true;
754}
755
746struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { 756struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
747 .get_modes = radeon_dvi_get_modes, 757 .get_modes = radeon_dvi_get_modes,
748 .mode_valid = radeon_vga_mode_valid, 758 .mode_valid = radeon_vga_mode_valid,
@@ -755,6 +765,7 @@ struct drm_connector_funcs radeon_dvi_connector_funcs = {
755 .fill_modes = drm_helper_probe_single_connector_modes, 765 .fill_modes = drm_helper_probe_single_connector_modes,
756 .set_property = radeon_connector_set_property, 766 .set_property = radeon_connector_set_property,
757 .destroy = radeon_connector_destroy, 767 .destroy = radeon_connector_destroy,
768 .force = radeon_dvi_force,
758}; 769};
759 770
760void 771void
@@ -771,6 +782,7 @@ radeon_add_atom_connector(struct drm_device *dev,
771 struct radeon_connector *radeon_connector; 782 struct radeon_connector *radeon_connector;
772 struct radeon_connector_atom_dig *radeon_dig_connector; 783 struct radeon_connector_atom_dig *radeon_dig_connector;
773 uint32_t subpixel_order = SubPixelNone; 784 uint32_t subpixel_order = SubPixelNone;
785 int ret;
774 786
775 /* fixme - tv/cv/din */ 787 /* fixme - tv/cv/din */
776 if (connector_type == DRM_MODE_CONNECTOR_Unknown) 788 if (connector_type == DRM_MODE_CONNECTOR_Unknown)
@@ -914,6 +926,10 @@ radeon_add_atom_connector(struct drm_device *dev,
914 break; 926 break;
915 } 927 }
916 928
929 ret = drm_fb_helper_add_connector(connector);
930 if (ret)
931 goto failed;
932
917 connector->display_info.subpixel_order = subpixel_order; 933 connector->display_info.subpixel_order = subpixel_order;
918 drm_sysfs_connector_add(connector); 934 drm_sysfs_connector_add(connector);
919 return; 935 return;
@@ -936,6 +952,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
936 struct drm_connector *connector; 952 struct drm_connector *connector;
937 struct radeon_connector *radeon_connector; 953 struct radeon_connector *radeon_connector;
938 uint32_t subpixel_order = SubPixelNone; 954 uint32_t subpixel_order = SubPixelNone;
955 int ret;
939 956
940 /* fixme - tv/cv/din */ 957 /* fixme - tv/cv/din */
941 if (connector_type == DRM_MODE_CONNECTOR_Unknown) 958 if (connector_type == DRM_MODE_CONNECTOR_Unknown)
@@ -1027,6 +1044,10 @@ radeon_add_legacy_connector(struct drm_device *dev,
1027 break; 1044 break;
1028 } 1045 }
1029 1046
1047 ret = drm_fb_helper_add_connector(connector);
1048 if (ret)
1049 goto failed;
1050
1030 connector->display_info.subpixel_order = subpixel_order; 1051 connector->display_info.subpixel_order = subpixel_order;
1031 drm_sysfs_connector_add(connector); 1052 drm_sysfs_connector_add(connector);
1032 return; 1053 return;
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 944e4fa78db5..1ba704eedefb 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -128,6 +128,7 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
128int radeonfb_create(struct drm_device *dev, 128int radeonfb_create(struct drm_device *dev,
129 uint32_t fb_width, uint32_t fb_height, 129 uint32_t fb_width, uint32_t fb_height,
130 uint32_t surface_width, uint32_t surface_height, 130 uint32_t surface_width, uint32_t surface_height,
131 uint32_t surface_depth, uint32_t surface_bpp,
131 struct drm_framebuffer **fb_p) 132 struct drm_framebuffer **fb_p)
132{ 133{
133 struct radeon_device *rdev = dev->dev_private; 134 struct radeon_device *rdev = dev->dev_private;
@@ -148,10 +149,10 @@ int radeonfb_create(struct drm_device *dev,
148 149
149 mode_cmd.width = surface_width; 150 mode_cmd.width = surface_width;
150 mode_cmd.height = surface_height; 151 mode_cmd.height = surface_height;
151 mode_cmd.bpp = 32; 152 mode_cmd.bpp = surface_bpp;
152 /* need to align pitch with crtc limits */ 153 /* need to align pitch with crtc limits */
153 mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8); 154 mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8);
154 mode_cmd.depth = 24; 155 mode_cmd.depth = surface_depth;
155 156
156 size = mode_cmd.pitch * mode_cmd.height; 157 size = mode_cmd.pitch * mode_cmd.height;
157 aligned_size = ALIGN(size, PAGE_SIZE); 158 aligned_size = ALIGN(size, PAGE_SIZE);
@@ -290,13 +291,26 @@ out:
290 return ret; 291 return ret;
291} 292}
292 293
294static char *mode_option;
295int radeon_parse_options(char *options)
296{
297 char *this_opt;
298
299 if (!options || !*options)
300 return 0;
301
302 while ((this_opt = strsep(&options, ",")) != NULL) {
303 if (!*this_opt)
304 continue;
305 mode_option = this_opt;
306 }
307 return 0;
308}
309
293int radeonfb_probe(struct drm_device *dev) 310int radeonfb_probe(struct drm_device *dev)
294{ 311{
295 int ret; 312 return drm_fb_helper_single_fb_probe(dev, &radeonfb_create);
296 ret = drm_fb_helper_single_fb_probe(dev, &radeonfb_create);
297 return ret;
298} 313}
299EXPORT_SYMBOL(radeonfb_probe);
300 314
301int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) 315int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
302{ 316{
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index ae1e9e166959..b69347b8904f 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -387,6 +387,7 @@ struct drm_crtc {
387 * @get_modes: get mode list for this connector 387 * @get_modes: get mode list for this connector
388 * @set_property: property for this connector may need update 388 * @set_property: property for this connector may need update
389 * @destroy: make object go away 389 * @destroy: make object go away
390 * @force: notify the driver the connector is forced on
390 * 391 *
391 * Each CRTC may have one or more connectors attached to it. The functions 392 * Each CRTC may have one or more connectors attached to it. The functions
392 * below allow the core DRM code to control connectors, enumerate available modes, 393 * below allow the core DRM code to control connectors, enumerate available modes,
@@ -401,6 +402,7 @@ struct drm_connector_funcs {
401 int (*set_property)(struct drm_connector *connector, struct drm_property *property, 402 int (*set_property)(struct drm_connector *connector, struct drm_property *property,
402 uint64_t val); 403 uint64_t val);
403 void (*destroy)(struct drm_connector *connector); 404 void (*destroy)(struct drm_connector *connector);
405 void (*force)(struct drm_connector *connector);
404}; 406};
405 407
406struct drm_encoder_funcs { 408struct drm_encoder_funcs {
@@ -429,6 +431,13 @@ struct drm_encoder {
429 void *helper_private; 431 void *helper_private;
430}; 432};
431 433
434enum drm_connector_force {
435 DRM_FORCE_UNSPECIFIED,
436 DRM_FORCE_OFF,
437 DRM_FORCE_ON, /* force on analog part normally */
438 DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */
439};
440
432/** 441/**
433 * drm_connector - central DRM connector control structure 442 * drm_connector - central DRM connector control structure
434 * @crtc: CRTC this connector is currently connected to, NULL if none 443 * @crtc: CRTC this connector is currently connected to, NULL if none
@@ -478,9 +487,12 @@ struct drm_connector {
478 487
479 void *helper_private; 488 void *helper_private;
480 489
490 /* forced on connector */
491 enum drm_connector_force force;
481 uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; 492 uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
482 uint32_t force_encoder_id; 493 uint32_t force_encoder_id;
483 struct drm_encoder *encoder; /* currently active encoder */ 494 struct drm_encoder *encoder; /* currently active encoder */
495 void *fb_helper_private;
484}; 496};
485 497
486/** 498/**
@@ -746,7 +758,7 @@ extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
746extern bool drm_detect_hdmi_monitor(struct edid *edid); 758extern bool drm_detect_hdmi_monitor(struct edid *edid);
747extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, 759extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
748 int hdisplay, int vdisplay, int vrefresh, 760 int hdisplay, int vdisplay, int vrefresh,
749 bool reduced, bool interlaced); 761 bool reduced, bool interlaced, bool margins);
750extern struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, 762extern struct drm_display_mode *drm_gtf_mode(struct drm_device *dev,
751 int hdisplay, int vdisplay, int vrefresh, 763 int hdisplay, int vdisplay, int vrefresh,
752 bool interlaced, int margins); 764 bool interlaced, int margins);
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 88fffbdfa26f..4aa5740ce59f 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -35,11 +35,30 @@ struct drm_fb_helper_crtc {
35 struct drm_mode_set mode_set; 35 struct drm_mode_set mode_set;
36}; 36};
37 37
38
38struct drm_fb_helper_funcs { 39struct drm_fb_helper_funcs {
39 void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green, 40 void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
40 u16 blue, int regno); 41 u16 blue, int regno);
41}; 42};
42 43
44/* mode specified on the command line */
45struct drm_fb_helper_cmdline_mode {
46 bool specified;
47 bool refresh_specified;
48 bool bpp_specified;
49 int xres, yres;
50 int bpp;
51 int refresh;
52 bool rb;
53 bool interlace;
54 bool cvt;
55 bool margins;
56};
57
58struct drm_fb_helper_connector {
59 struct drm_fb_helper_cmdline_mode cmdline_mode;
60};
61
43struct drm_fb_helper { 62struct drm_fb_helper {
44 struct drm_framebuffer *fb; 63 struct drm_framebuffer *fb;
45 struct drm_device *dev; 64 struct drm_device *dev;
@@ -57,6 +76,8 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
57 uint32_t fb_height, 76 uint32_t fb_height,
58 uint32_t surface_width, 77 uint32_t surface_width,
59 uint32_t surface_height, 78 uint32_t surface_height,
79 uint32_t surface_depth,
80 uint32_t surface_bpp,
60 struct drm_framebuffer **fb_ptr)); 81 struct drm_framebuffer **fb_ptr));
61int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, 82int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count,
62 int max_conn); 83 int max_conn);
@@ -79,4 +100,7 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
79 uint32_t fb_width, uint32_t fb_height); 100 uint32_t fb_width, uint32_t fb_height);
80void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch); 101void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch);
81 102
103int drm_fb_helper_add_connector(struct drm_connector *connector);
104int drm_fb_helper_parse_command_line(struct drm_device *dev);
105
82#endif 106#endif