aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_fb_helper.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/gpu/drm/drm_fb_helper.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'drivers/gpu/drm/drm_fb_helper.c')
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c321
1 files changed, 136 insertions, 185 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 6a5e403f9aa1..802b61ac3139 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -70,176 +70,76 @@ fail:
70} 70}
71EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); 71EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
72 72
73/** 73static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
74 * drm_fb_helper_connector_parse_command_line - parse command line for connector
75 * @connector - connector to parse line for
76 * @mode_option - per connector mode option
77 *
78 * This parses the connector specific then generic command lines for
79 * modes and options to configure the connector.
80 *
81 * This uses the same parameters as the fb modedb.c, except for extra
82 * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
83 *
84 * enable/enable Digital/disable bit at the end
85 */
86static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
87 const char *mode_option)
88{ 74{
89 const char *name; 75 struct drm_fb_helper_connector *fb_helper_conn;
90 unsigned int namelen;
91 int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
92 unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
93 int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
94 int i; 76 int i;
95 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
96 struct drm_fb_helper_cmdline_mode *cmdline_mode;
97 struct drm_connector *connector;
98
99 if (!fb_helper_conn)
100 return false;
101 connector = fb_helper_conn->connector;
102 77
103 cmdline_mode = &fb_helper_conn->cmdline_mode; 78 for (i = 0; i < fb_helper->connector_count; i++) {
104 if (!mode_option) 79 struct drm_cmdline_mode *mode;
105 mode_option = fb_mode_option; 80 struct drm_connector *connector;
106 81 char *option = NULL;
107 if (!mode_option) {
108 cmdline_mode->specified = false;
109 return false;
110 }
111 82
112 name = mode_option; 83 fb_helper_conn = fb_helper->connector_info[i];
113 namelen = strlen(name); 84 connector = fb_helper_conn->connector;
114 for (i = namelen-1; i >= 0; i--) { 85 mode = &fb_helper_conn->cmdline_mode;
115 switch (name[i]) {
116 case '@':
117 namelen = i;
118 if (!refresh_specified && !bpp_specified &&
119 !yres_specified) {
120 refresh = simple_strtol(&name[i+1], NULL, 10);
121 refresh_specified = 1;
122 if (cvt || rb)
123 cvt = 0;
124 } else
125 goto done;
126 break;
127 case '-':
128 namelen = i;
129 if (!bpp_specified && !yres_specified) {
130 bpp = simple_strtol(&name[i+1], NULL, 10);
131 bpp_specified = 1;
132 if (cvt || rb)
133 cvt = 0;
134 } else
135 goto done;
136 break;
137 case 'x':
138 if (!yres_specified) {
139 yres = simple_strtol(&name[i+1], NULL, 10);
140 yres_specified = 1;
141 } else
142 goto done;
143 case '0' ... '9':
144 break;
145 case 'M':
146 if (!yres_specified)
147 cvt = 1;
148 break;
149 case 'R':
150 if (cvt)
151 rb = 1;
152 break;
153 case 'm':
154 if (!cvt)
155 margins = 1;
156 break;
157 case 'i':
158 if (!cvt)
159 interlace = 1;
160 break;
161 case 'e':
162 force = DRM_FORCE_ON;
163 break;
164 case 'D':
165 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
166 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
167 force = DRM_FORCE_ON;
168 else
169 force = DRM_FORCE_ON_DIGITAL;
170 break;
171 case 'd':
172 force = DRM_FORCE_OFF;
173 break;
174 default:
175 goto done;
176 }
177 }
178 if (i < 0 && yres_specified) {
179 xres = simple_strtol(name, NULL, 10);
180 res_specified = 1;
181 }
182done:
183
184 DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
185 drm_get_connector_name(connector), xres, yres,
186 (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
187 "", (margins) ? " with margins" : "", (interlace) ?
188 " interlaced" : "");
189
190 if (force) {
191 const char *s;
192 switch (force) {
193 case DRM_FORCE_OFF: s = "OFF"; break;
194 case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
195 default:
196 case DRM_FORCE_ON: s = "ON"; break;
197 }
198 86
199 DRM_INFO("forcing %s connector %s\n", 87 /* do something on return - turn off connector maybe */
200 drm_get_connector_name(connector), s); 88 if (fb_get_options(drm_get_connector_name(connector), &option))
201 connector->force = force; 89 continue;
202 }
203 90
204 if (res_specified) { 91 if (drm_mode_parse_command_line_for_connector(option,
205 cmdline_mode->specified = true; 92 connector,
206 cmdline_mode->xres = xres; 93 mode)) {
207 cmdline_mode->yres = yres; 94 if (mode->force) {
208 } 95 const char *s;
96 switch (mode->force) {
97 case DRM_FORCE_OFF: s = "OFF"; break;
98 case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
99 default:
100 case DRM_FORCE_ON: s = "ON"; break;
101 }
102
103 DRM_INFO("forcing %s connector %s\n",
104 drm_get_connector_name(connector), s);
105 connector->force = mode->force;
106 }
209 107
210 if (refresh_specified) { 108 DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
211 cmdline_mode->refresh_specified = true; 109 drm_get_connector_name(connector),
212 cmdline_mode->refresh = refresh; 110 mode->xres, mode->yres,
213 } 111 mode->refresh_specified ? mode->refresh : 60,
112 mode->rb ? " reduced blanking" : "",
113 mode->margins ? " with margins" : "",
114 mode->interlace ? " interlaced" : "");
115 }
214 116
215 if (bpp_specified) {
216 cmdline_mode->bpp_specified = true;
217 cmdline_mode->bpp = bpp;
218 } 117 }
219 cmdline_mode->rb = rb ? true : false; 118 return 0;
220 cmdline_mode->cvt = cvt ? true : false;
221 cmdline_mode->interlace = interlace ? true : false;
222
223 return true;
224} 119}
225 120
226static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) 121static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
227{ 122{
228 struct drm_fb_helper_connector *fb_helper_conn; 123 uint16_t *r_base, *g_base, *b_base;
229 int i; 124 int i;
230 125
231 for (i = 0; i < fb_helper->connector_count; i++) { 126 r_base = crtc->gamma_store;
232 char *option = NULL; 127 g_base = r_base + crtc->gamma_size;
128 b_base = g_base + crtc->gamma_size;
233 129
234 fb_helper_conn = fb_helper->connector_info[i]; 130 for (i = 0; i < crtc->gamma_size; i++)
131 helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
132}
235 133
236 /* do something on return - turn off connector maybe */ 134static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
237 if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option)) 135{
238 continue; 136 uint16_t *r_base, *g_base, *b_base;
239 137
240 drm_fb_helper_connector_parse_command_line(fb_helper_conn, option); 138 r_base = crtc->gamma_store;
241 } 139 g_base = r_base + crtc->gamma_size;
242 return 0; 140 b_base = g_base + crtc->gamma_size;
141
142 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
243} 143}
244 144
245int drm_fb_helper_debug_enter(struct fb_info *info) 145int drm_fb_helper_debug_enter(struct fb_info *info)
@@ -260,11 +160,12 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
260 continue; 160 continue;
261 161
262 funcs = mode_set->crtc->helper_private; 162 funcs = mode_set->crtc->helper_private;
163 drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
263 funcs->mode_set_base_atomic(mode_set->crtc, 164 funcs->mode_set_base_atomic(mode_set->crtc,
264 mode_set->fb, 165 mode_set->fb,
265 mode_set->x, 166 mode_set->x,
266 mode_set->y); 167 mode_set->y,
267 168 ENTER_ATOMIC_MODE_SET);
268 } 169 }
269 } 170 }
270 171
@@ -308,17 +209,31 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
308 continue; 209 continue;
309 } 210 }
310 211
212 drm_fb_helper_restore_lut_atomic(mode_set->crtc);
311 funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, 213 funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
312 crtc->y); 214 crtc->y, LEAVE_ATOMIC_MODE_SET);
313 } 215 }
314 216
315 return 0; 217 return 0;
316} 218}
317EXPORT_SYMBOL(drm_fb_helper_debug_leave); 219EXPORT_SYMBOL(drm_fb_helper_debug_leave);
318 220
221bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
222{
223 bool error = false;
224 int i, ret;
225 for (i = 0; i < fb_helper->crtc_count; i++) {
226 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
227 ret = drm_crtc_helper_set_config(mode_set);
228 if (ret)
229 error = true;
230 }
231 return error;
232}
233EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode);
234
319bool drm_fb_helper_force_kernel_mode(void) 235bool drm_fb_helper_force_kernel_mode(void)
320{ 236{
321 int i = 0;
322 bool ret, error = false; 237 bool ret, error = false;
323 struct drm_fb_helper *helper; 238 struct drm_fb_helper *helper;
324 239
@@ -326,12 +241,12 @@ bool drm_fb_helper_force_kernel_mode(void)
326 return false; 241 return false;
327 242
328 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { 243 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
329 for (i = 0; i < helper->crtc_count; i++) { 244 if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
330 struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; 245 continue;
331 ret = drm_crtc_helper_set_config(mode_set); 246
332 if (ret) 247 ret = drm_fb_helper_restore_fbdev_mode(helper);
333 error = true; 248 if (ret)
334 } 249 error = true;
335 } 250 }
336 return error; 251 return error;
337} 252}
@@ -601,6 +516,11 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
601 value = (red << info->var.red.offset) | 516 value = (red << info->var.red.offset) |
602 (green << info->var.green.offset) | 517 (green << info->var.green.offset) |
603 (blue << info->var.blue.offset); 518 (blue << info->var.blue.offset);
519 if (info->var.transp.length > 0) {
520 u32 mask = (1 << info->var.transp.length) - 1;
521 mask <<= info->var.transp.offset;
522 value |= mask;
523 }
604 palette[regno] = value; 524 palette[regno] = value;
605 return 0; 525 return 0;
606 } 526 }
@@ -646,7 +566,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
646 struct drm_crtc_helper_funcs *crtc_funcs; 566 struct drm_crtc_helper_funcs *crtc_funcs;
647 u16 *red, *green, *blue, *transp; 567 u16 *red, *green, *blue, *transp;
648 struct drm_crtc *crtc; 568 struct drm_crtc *crtc;
649 int i, rc = 0; 569 int i, j, rc = 0;
650 int start; 570 int start;
651 571
652 for (i = 0; i < fb_helper->crtc_count; i++) { 572 for (i = 0; i < fb_helper->crtc_count; i++) {
@@ -659,7 +579,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
659 transp = cmap->transp; 579 transp = cmap->transp;
660 start = cmap->start; 580 start = cmap->start;
661 581
662 for (i = 0; i < cmap->len; i++) { 582 for (j = 0; j < cmap->len; j++) {
663 u16 hred, hgreen, hblue, htransp = 0xffff; 583 u16 hred, hgreen, hblue, htransp = 0xffff;
664 584
665 hred = *red++; 585 hred = *red++;
@@ -857,7 +777,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
857 /* first up get a count of crtcs now in use and new min/maxes width/heights */ 777 /* first up get a count of crtcs now in use and new min/maxes width/heights */
858 for (i = 0; i < fb_helper->connector_count; i++) { 778 for (i = 0; i < fb_helper->connector_count; i++) {
859 struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; 779 struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
860 struct drm_fb_helper_cmdline_mode *cmdline_mode; 780 struct drm_cmdline_mode *cmdline_mode;
861 781
862 cmdline_mode = &fb_helper_conn->cmdline_mode; 782 cmdline_mode = &fb_helper_conn->cmdline_mode;
863 783
@@ -959,6 +879,8 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
959 info->fix.type = FB_TYPE_PACKED_PIXELS; 879 info->fix.type = FB_TYPE_PACKED_PIXELS;
960 info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : 880 info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
961 FB_VISUAL_TRUECOLOR; 881 FB_VISUAL_TRUECOLOR;
882 info->fix.mmio_start = 0;
883 info->fix.mmio_len = 0;
962 info->fix.type_aux = 0; 884 info->fix.type_aux = 0;
963 info->fix.xpanstep = 1; /* doing it in hw */ 885 info->fix.xpanstep = 1; /* doing it in hw */
964 info->fix.ypanstep = 1; /* doing it in hw */ 886 info->fix.ypanstep = 1; /* doing it in hw */
@@ -979,6 +901,7 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
979 info->var.xres_virtual = fb->width; 901 info->var.xres_virtual = fb->width;
980 info->var.yres_virtual = fb->height; 902 info->var.yres_virtual = fb->height;
981 info->var.bits_per_pixel = fb->bits_per_pixel; 903 info->var.bits_per_pixel = fb->bits_per_pixel;
904 info->var.accel_flags = FB_ACCELF_TEXT;
982 info->var.xoffset = 0; 905 info->var.xoffset = 0;
983 info->var.yoffset = 0; 906 info->var.yoffset = 0;
984 info->var.activate = FB_ACTIVATE_NOW; 907 info->var.activate = FB_ACTIVATE_NOW;
@@ -1076,7 +999,7 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_conn
1076 999
1077static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) 1000static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
1078{ 1001{
1079 struct drm_fb_helper_cmdline_mode *cmdline_mode; 1002 struct drm_cmdline_mode *cmdline_mode;
1080 cmdline_mode = &fb_connector->cmdline_mode; 1003 cmdline_mode = &fb_connector->cmdline_mode;
1081 return cmdline_mode->specified; 1004 return cmdline_mode->specified;
1082} 1005}
@@ -1084,7 +1007,7 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
1084static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, 1007static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
1085 int width, int height) 1008 int width, int height)
1086{ 1009{
1087 struct drm_fb_helper_cmdline_mode *cmdline_mode; 1010 struct drm_cmdline_mode *cmdline_mode;
1088 struct drm_display_mode *mode = NULL; 1011 struct drm_display_mode *mode = NULL;
1089 1012
1090 cmdline_mode = &fb_helper_conn->cmdline_mode; 1013 cmdline_mode = &fb_helper_conn->cmdline_mode;
@@ -1116,19 +1039,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
1116 } 1039 }
1117 1040
1118create_mode: 1041create_mode:
1119 if (cmdline_mode->cvt) 1042 mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
1120 mode = drm_cvt_mode(fb_helper_conn->connector->dev, 1043 cmdline_mode);
1121 cmdline_mode->xres, cmdline_mode->yres,
1122 cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
1123 cmdline_mode->rb, cmdline_mode->interlace,
1124 cmdline_mode->margins);
1125 else
1126 mode = drm_gtf_mode(fb_helper_conn->connector->dev,
1127 cmdline_mode->xres, cmdline_mode->yres,
1128 cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
1129 cmdline_mode->interlace,
1130 cmdline_mode->margins);
1131 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1132 list_add(&mode->head, &fb_helper_conn->connector->modes); 1044 list_add(&mode->head, &fb_helper_conn->connector->modes);
1133 return mode; 1045 return mode;
1134} 1046}
@@ -1469,17 +1381,33 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1469} 1381}
1470EXPORT_SYMBOL(drm_fb_helper_initial_config); 1382EXPORT_SYMBOL(drm_fb_helper_initial_config);
1471 1383
1472bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) 1384/**
1385 * drm_fb_helper_hotplug_event - respond to a hotplug notification by
1386 * probing all the outputs attached to the fb.
1387 * @fb_helper: the drm_fb_helper
1388 *
1389 * LOCKING:
1390 * Called at runtime, must take mode config lock.
1391 *
1392 * Scan the connectors attached to the fb_helper and try to put together a
1393 * setup after *notification of a change in output configuration.
1394 *
1395 * RETURNS:
1396 * 0 on success and a non-zero error code otherwise.
1397 */
1398int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1473{ 1399{
1400 struct drm_device *dev = fb_helper->dev;
1474 int count = 0; 1401 int count = 0;
1475 u32 max_width, max_height, bpp_sel; 1402 u32 max_width, max_height, bpp_sel;
1476 bool bound = false, crtcs_bound = false; 1403 bool bound = false, crtcs_bound = false;
1477 struct drm_crtc *crtc; 1404 struct drm_crtc *crtc;
1478 1405
1479 if (!fb_helper->fb) 1406 if (!fb_helper->fb)
1480 return false; 1407 return 0;
1481 1408
1482 list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) { 1409 mutex_lock(&dev->mode_config.mutex);
1410 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1483 if (crtc->fb) 1411 if (crtc->fb)
1484 crtcs_bound = true; 1412 crtcs_bound = true;
1485 if (crtc->fb == fb_helper->fb) 1413 if (crtc->fb == fb_helper->fb)
@@ -1488,7 +1416,8 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1488 1416
1489 if (!bound && crtcs_bound) { 1417 if (!bound && crtcs_bound) {
1490 fb_helper->delayed_hotplug = true; 1418 fb_helper->delayed_hotplug = true;
1491 return false; 1419 mutex_unlock(&dev->mode_config.mutex);
1420 return 0;
1492 } 1421 }
1493 DRM_DEBUG_KMS("\n"); 1422 DRM_DEBUG_KMS("\n");
1494 1423
@@ -1499,8 +1428,30 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1499 count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, 1428 count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
1500 max_height); 1429 max_height);
1501 drm_setup_crtcs(fb_helper); 1430 drm_setup_crtcs(fb_helper);
1431 mutex_unlock(&dev->mode_config.mutex);
1502 1432
1503 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); 1433 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1504} 1434}
1505EXPORT_SYMBOL(drm_fb_helper_hotplug_event); 1435EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
1506 1436
1437/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
1438 * but the module doesn't depend on any fb console symbols. At least
1439 * attempt to load fbcon to avoid leaving the system without a usable console.
1440 */
1441#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
1442static int __init drm_fb_helper_modinit(void)
1443{
1444 const char *name = "fbcon";
1445 struct module *fbcon;
1446
1447 mutex_lock(&module_mutex);
1448 fbcon = find_module(name);
1449 mutex_unlock(&module_mutex);
1450
1451 if (!fbcon)
1452 request_module_nowait(name);
1453 return 0;
1454}
1455
1456module_init(drm_fb_helper_modinit);
1457#endif