30 #include <linux/kernel.h>
32 #include <linux/slab.h>
34 #include <linux/module.h>
57 if (!fb_helper_connector)
74 static int drm_fb_helper_parse_command_line(
struct drm_fb_helper *fb_helper)
80 struct drm_cmdline_mode *
mode;
97 switch (mode->force) {
104 DRM_INFO(
"forcing %s connector %s\n",
106 connector->
force = mode->force;
109 DRM_DEBUG_KMS(
"cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
111 mode->xres, mode->yres,
112 mode->refresh_specified ? mode->refresh : 60,
113 mode->rb ?
" reduced blanking" :
"",
114 mode->margins ?
" with margins" :
"",
115 mode->interlace ?
" interlaced" :
"");
132 helper->
funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
135 static void drm_fb_helper_restore_lut_atomic(
struct drm_crtc *crtc)
146 crtc->
funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->
gamma_size);
155 if (list_empty(&kernel_fb_helper_list))
163 if (!mode_set->
crtc->enabled)
166 funcs = mode_set->
crtc->helper_private;
167 drm_fb_helper_save_lut_atomic(mode_set->
crtc, helper);
204 crtc = mode_set->
crtc;
206 fb = drm_mode_config_fb(crtc);
212 DRM_ERROR(
"no fb to restore??\n");
216 drm_fb_helper_restore_lut_atomic(mode_set->
crtc);
231 ret = mode_set->
crtc->funcs->set_config(mode_set);
239 static bool drm_fb_helper_force_kernel_mode(
void)
244 if (list_empty(&kernel_fb_helper_list))
248 if (helper->
dev->switch_power_state == DRM_SWITCH_POWER_OFF)
268 printk(
KERN_ERR "panic occurred, switching back to text console\n");
269 return drm_fb_helper_force_kernel_mode();
285 ret = drm_fb_helper_force_kernel_mode();
287 DRM_ERROR(
"Failed to restore crtc configuration\n");
291 #ifdef CONFIG_MAGIC_SYSRQ
296 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
298 static void drm_fb_helper_sysrq(
int dummy1)
303 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
304 .handler = drm_fb_helper_sysrq,
305 .help_msg =
"force-fb(V)",
306 .action_msg =
"Restore framebuffer console",
309 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
312 static void drm_fb_helper_dpms(
struct fb_info *
info,
int dpms_mode)
333 connector->
funcs->dpms(connector, dpms_mode);
335 dev->mode_config.dpms_property, dpms_mode);
369 static void drm_fb_helper_crtc_free(
struct drm_fb_helper *helper)
386 int crtc_count,
int max_conn_count)
407 for (i = 0; i < crtc_count; i++) {
409 kcalloc(max_conn_count,
413 if (!fb_helper->
crtc_info[i].mode_set.connectors)
415 fb_helper->
crtc_info[
i].mode_set.num_connectors = 0;
426 drm_fb_helper_crtc_free(fb_helper);
435 if (list_empty(&kernel_fb_helper_list)) {
443 drm_fb_helper_crtc_free(fb_helper);
462 red >>= (16 - info->
var.red.length);
463 green >>= (16 - info->
var.green.length);
464 blue >>= (16 - info->
var.blue.length);
465 value = (red << info->
var.red.offset) |
466 (green << info->
var.green.offset) |
467 (blue << info->
var.blue.offset);
468 if (info->
var.transp.length > 0) {
469 u32 mask = (1 << info->
var.transp.length) - 1;
470 mask <<= info->
var.transp.offset;
473 palette[regno] =
value;
482 if (fb->
depth == 16 && regno > 63)
484 if (fb->
depth == 15 && regno > 31)
487 if (fb->
depth == 16) {
491 for (i = 0; i < 8; i++)
492 fb_helper->
funcs->gamma_set(crtc, red,
493 green, blue, pindex + i);
496 fb_helper->
funcs->gamma_get(crtc, &r,
500 for (i = 0; i < 4; i++)
501 fb_helper->
funcs->gamma_set(crtc, r,
508 fb_helper->
funcs->gamma_set(crtc, red, green, blue, pindex);
531 for (j = 0; j < cmap->
len; j++) {
532 u16 hred, hgreen, hblue, htransp = 0xffff;
541 rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
565 DRM_DEBUG(
"fb userspace requested width/height/bpp is greater than current fb "
566 "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
575 depth = (var->
green.length == 6) ? 16 : 15;
578 depth = (var->
transp.length > 0) ? 32 : 24;
588 var->
green.offset = 0;
589 var->
blue.offset = 0;
591 var->
green.length = 8;
592 var->
blue.length = 8;
597 var->
red.offset = 10;
598 var->
green.offset = 5;
599 var->
blue.offset = 0;
601 var->
green.length = 5;
602 var->
blue.length = 5;
607 var->
red.offset = 11;
608 var->
green.offset = 5;
609 var->
blue.offset = 0;
611 var->
green.length = 6;
612 var->
blue.length = 5;
617 var->
red.offset = 16;
618 var->
green.offset = 8;
619 var->
blue.offset = 0;
621 var->
green.length = 8;
622 var->
blue.length = 8;
627 var->
red.offset = 16;
628 var->
green.offset = 8;
629 var->
blue.offset = 0;
631 var->
green.length = 8;
632 var->
blue.length = 8;
654 DRM_ERROR(
"PIXEL CLOCK SET\n");
697 ret = crtc->
funcs->set_config(modeset);
733 struct drm_cmdline_mode *cmdline_mode;
737 if (cmdline_mode->bpp_specified) {
738 switch (cmdline_mode->bpp) {
764 desired_mode = fb_helper->
crtc_info[
i].desired_mode;
768 gamma_size = fb_helper->
crtc_info[
i].mode_set.crtc->gamma_size;
784 DRM_INFO(
"Cannot find any crtc or sizes - going 1024x768\n");
790 new_fb = (*fb_helper->
funcs->fb_probe)(fb_helper, &sizes);
794 info = fb_helper->
fbdev;
802 info->
var.pixclock = 0;
816 if (list_empty(&kernel_fb_helper_list)) {
835 info->
fix.mmio_start = 0;
836 info->
fix.mmio_len = 0;
837 info->
fix.type_aux = 0;
838 info->
fix.xpanstep = 1;
839 info->
fix.ypanstep = 1;
840 info->
fix.ywrapstep = 0;
842 info->
fix.type_aux = 0;
844 info->
fix.line_length = pitch;
858 info->
var.xoffset = 0;
859 info->
var.yoffset = 0;
861 info->
var.height = -1;
862 info->
var.width = -1;
866 info->
var.red.offset = 0;
867 info->
var.green.offset = 0;
868 info->
var.blue.offset = 0;
869 info->
var.red.length = 8;
870 info->
var.green.length = 8;
871 info->
var.blue.length = 8;
872 info->
var.transp.offset = 0;
873 info->
var.transp.length = 0;
876 info->
var.red.offset = 10;
877 info->
var.green.offset = 5;
878 info->
var.blue.offset = 0;
879 info->
var.red.length = 5;
880 info->
var.green.length = 5;
881 info->
var.blue.length = 5;
882 info->
var.transp.offset = 15;
883 info->
var.transp.length = 1;
886 info->
var.red.offset = 11;
887 info->
var.green.offset = 5;
888 info->
var.blue.offset = 0;
889 info->
var.red.length = 5;
890 info->
var.green.length = 6;
891 info->
var.blue.length = 5;
892 info->
var.transp.offset = 0;
895 info->
var.red.offset = 16;
896 info->
var.green.offset = 8;
897 info->
var.blue.offset = 0;
898 info->
var.red.length = 8;
899 info->
var.green.length = 8;
900 info->
var.blue.length = 8;
901 info->
var.transp.offset = 0;
902 info->
var.transp.length = 0;
905 info->
var.red.offset = 16;
906 info->
var.green.offset = 8;
907 info->
var.blue.offset = 0;
908 info->
var.red.length = 8;
909 info->
var.green.length = 8;
910 info->
var.blue.length = 8;
911 info->
var.transp.offset = 24;
912 info->
var.transp.length = 8;
918 info->
var.xres = fb_width;
919 info->
var.yres = fb_height;
923 static int drm_fb_helper_probe_connector_modes(
struct drm_fb_helper *fb_helper,
933 count += connector->
funcs->fill_modes(connector, maxX, maxY);
955 struct drm_cmdline_mode *cmdline_mode;
957 return cmdline_mode->specified;
961 int width,
int height)
963 struct drm_cmdline_mode *cmdline_mode;
967 if (cmdline_mode->specified ==
false)
973 if (cmdline_mode->rb || cmdline_mode->margins)
978 if (mode->
hdisplay != cmdline_mode->xres ||
979 mode->
vdisplay != cmdline_mode->yres)
982 if (cmdline_mode->refresh_specified) {
983 if (mode->
vrefresh != cmdline_mode->refresh)
987 if (cmdline_mode->interlace) {
1001 static bool drm_connector_enabled(
struct drm_connector *connector,
bool strict)
1013 static void drm_enable_connectors(
struct drm_fb_helper *fb_helper,
1016 bool any_enabled =
false;
1022 enabled[
i] = drm_connector_enabled(connector,
true);
1023 DRM_DEBUG_KMS(
"connector %d enabled? %s\n", connector->
base.id,
1024 enabled[i] ?
"yes" :
"no");
1025 any_enabled |= enabled[
i];
1033 enabled[
i] = drm_connector_enabled(connector,
false);
1037 static bool drm_target_cloned(
struct drm_fb_helper *fb_helper,
1039 bool *enabled,
int width,
int height)
1042 bool can_clone =
false;
1066 modes[
i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1071 for (j = 0; j <
i; j++) {
1080 DRM_DEBUG_KMS(
"can clone using command line\n");
1103 DRM_DEBUG_KMS(
"can clone using 1024x768\n");
1106 DRM_INFO(
"kms: can't enable cloning when we probably wanted to.\n");
1110 static bool drm_target_preferred(
struct drm_fb_helper *fb_helper,
1112 bool *enabled,
int width,
int height)
1120 if (enabled[i] ==
false)
1123 DRM_DEBUG_KMS(
"looking for cmdline mode on connector %d\n",
1127 modes[
i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1129 DRM_DEBUG_KMS(
"looking for preferred mode on connector %d\n",
1131 modes[
i] = drm_has_preferred_mode(fb_helper_conn, width, height);
1134 if (!modes[i] && !list_empty(&fb_helper_conn->
connector->modes)) {
1138 DRM_DEBUG_KMS("found mode %
s\
n", modes[i] ? modes[i]->
name :
1147 int n,
int width,
int height)
1155 int my_score, best_score,
score;
1159 if (n == fb_helper->connector_count)
1162 fb_helper_conn = fb_helper->connector_info[
n];
1165 best_crtcs[
n] =
NULL;
1167 best_score =
drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
1168 if (modes[n] ==
NULL)
1171 crtcs = kzalloc(dev->mode_config.num_connector *
1179 if (drm_has_cmdline_mode(fb_helper_conn))
1181 if (drm_has_preferred_mode(fb_helper_conn, width, height))
1191 for (c = 0; c < fb_helper->crtc_count; c++) {
1192 crtc = &fb_helper->crtc_info[
c];
1198 for (o = 0; o <
n; o++)
1199 if (best_crtcs[o] == crtc)
1204 if (fb_helper->crtc_count > 1)
1213 score = my_score +
drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
1215 if (score > best_score) {
1218 memcpy(best_crtcs, crtcs,
1219 dev->mode_config.num_connector *
1228 static void drm_setup_crtcs(
struct drm_fb_helper *fb_helper)
1238 DRM_DEBUG_KMS(
"\n");
1240 width = dev->mode_config.max_width;
1241 height = dev->mode_config.max_height;
1243 crtcs = kcalloc(dev->mode_config.num_connector,
1245 modes = kcalloc(dev->mode_config.num_connector,
1247 enabled = kcalloc(dev->mode_config.num_connector,
1250 drm_enable_connectors(fb_helper, enabled);
1252 ret = drm_target_cloned(fb_helper, modes, enabled, width, height);
1254 ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
1256 DRM_ERROR(
"Unable to find initial modes\n");
1259 DRM_DEBUG_KMS(
"picking CRTCs for %dx%d config\n", width, height);
1265 for (i = 0; i < fb_helper->
crtc_count; i++) {
1275 if (mode && fb_crtc) {
1276 DRM_DEBUG_KMS(
"desired mode %s set on crtc %d\n",
1314 drm_fb_helper_parse_command_line(fb_helper);
1316 count = drm_fb_helper_probe_connector_modes(fb_helper,
1317 dev->mode_config.max_width,
1318 dev->mode_config.max_height);
1325 drm_setup_crtcs(fb_helper);
1350 int bound = 0, crtcs_bound = 0;
1360 if (crtc->
fb == fb_helper->
fb)
1364 if (bound < crtcs_bound) {
1369 DRM_DEBUG_KMS(
"\n");
1371 max_width = fb_helper->
fb->width;
1372 max_height = fb_helper->
fb->height;
1373 bpp_sel = fb_helper->
fb->bits_per_pixel;
1375 count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
1377 drm_setup_crtcs(fb_helper);
1388 #if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
1389 static int __init drm_fb_helper_modinit(
void)
1391 const char *
name =
"fbcon";
1399 request_module_nowait(name);