aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_fb_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_fb_helper.c')
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c154
1 files changed, 122 insertions, 32 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 819ddcbfcce5..9c924614c418 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -454,6 +454,109 @@ out_free:
454} 454}
455EXPORT_SYMBOL(drm_fb_helper_init_crtc_count); 455EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
456 456
457static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
458 u16 blue, u16 regno, struct fb_info *info)
459{
460 struct drm_fb_helper *fb_helper = info->par;
461 struct drm_framebuffer *fb = fb_helper->fb;
462 int pindex;
463
464 if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
465 u32 *palette;
466 u32 value;
467 /* place color in psuedopalette */
468 if (regno > 16)
469 return -EINVAL;
470 palette = (u32 *)info->pseudo_palette;
471 red >>= (16 - info->var.red.length);
472 green >>= (16 - info->var.green.length);
473 blue >>= (16 - info->var.blue.length);
474 value = (red << info->var.red.offset) |
475 (green << info->var.green.offset) |
476 (blue << info->var.blue.offset);
477 palette[regno] = value;
478 return 0;
479 }
480
481 pindex = regno;
482
483 if (fb->bits_per_pixel == 16) {
484 pindex = regno << 3;
485
486 if (fb->depth == 16 && regno > 63)
487 return -EINVAL;
488 if (fb->depth == 15 && regno > 31)
489 return -EINVAL;
490
491 if (fb->depth == 16) {
492 u16 r, g, b;
493 int i;
494 if (regno < 32) {
495 for (i = 0; i < 8; i++)
496 fb_helper->funcs->gamma_set(crtc, red,
497 green, blue, pindex + i);
498 }
499
500 fb_helper->funcs->gamma_get(crtc, &r,
501 &g, &b,
502 pindex >> 1);
503
504 for (i = 0; i < 4; i++)
505 fb_helper->funcs->gamma_set(crtc, r,
506 green, b,
507 (pindex >> 1) + i);
508 }
509 }
510
511 if (fb->depth != 16)
512 fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
513 return 0;
514}
515
516int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
517{
518 struct drm_fb_helper *fb_helper = info->par;
519 struct drm_device *dev = fb_helper->dev;
520 u16 *red, *green, *blue, *transp;
521 struct drm_crtc *crtc;
522 int i, rc = 0;
523 int start;
524
525 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
526 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
527 for (i = 0; i < fb_helper->crtc_count; i++) {
528 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
529 break;
530 }
531 if (i == fb_helper->crtc_count)
532 continue;
533
534 red = cmap->red;
535 green = cmap->green;
536 blue = cmap->blue;
537 transp = cmap->transp;
538 start = cmap->start;
539
540 for (i = 0; i < cmap->len; i++) {
541 u16 hred, hgreen, hblue, htransp = 0xffff;
542
543 hred = *red++;
544 hgreen = *green++;
545 hblue = *blue++;
546
547 if (transp)
548 htransp = *transp++;
549
550 rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
551 if (rc)
552 return rc;
553 }
554 crtc_funcs->load_lut(crtc);
555 }
556 return rc;
557}
558EXPORT_SYMBOL(drm_fb_helper_setcmap);
559
457int drm_fb_helper_setcolreg(unsigned regno, 560int drm_fb_helper_setcolreg(unsigned regno,
458 unsigned red, 561 unsigned red,
459 unsigned green, 562 unsigned green,
@@ -465,10 +568,13 @@ int drm_fb_helper_setcolreg(unsigned regno,
465 struct drm_device *dev = fb_helper->dev; 568 struct drm_device *dev = fb_helper->dev;
466 struct drm_crtc *crtc; 569 struct drm_crtc *crtc;
467 int i; 570 int i;
571 int ret;
468 572
469 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 573 if (regno > 255)
470 struct drm_framebuffer *fb = fb_helper->fb; 574 return 1;
471 575
576 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
577 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
472 for (i = 0; i < fb_helper->crtc_count; i++) { 578 for (i = 0; i < fb_helper->crtc_count; i++) {
473 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) 579 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
474 break; 580 break;
@@ -476,35 +582,11 @@ int drm_fb_helper_setcolreg(unsigned regno,
476 if (i == fb_helper->crtc_count) 582 if (i == fb_helper->crtc_count)
477 continue; 583 continue;
478 584
479 if (regno > 255) 585 ret = setcolreg(crtc, red, green, blue, regno, info);
480 return 1; 586 if (ret)
481 587 return ret;
482 if (fb->depth == 8) {
483 fb_helper->funcs->gamma_set(crtc, red, green, blue, regno);
484 return 0;
485 }
486 588
487 if (regno < 16) { 589 crtc_funcs->load_lut(crtc);
488 switch (fb->depth) {
489 case 15:
490 fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
491 ((green & 0xf800) >> 6) |
492 ((blue & 0xf800) >> 11);
493 break;
494 case 16:
495 fb->pseudo_palette[regno] = (red & 0xf800) |
496 ((green & 0xfc00) >> 5) |
497 ((blue & 0xf800) >> 11);
498 break;
499 case 24:
500 case 32:
501 fb->pseudo_palette[regno] =
502 (((red >> 8) & 0xff) << info->var.red.offset) |
503 (((green >> 8) & 0xff) << info->var.green.offset) |
504 (((blue >> 8) & 0xff) << info->var.blue.offset);
505 break;
506 }
507 }
508 } 590 }
509 return 0; 591 return 0;
510} 592}
@@ -674,6 +756,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
674EXPORT_SYMBOL(drm_fb_helper_pan_display); 756EXPORT_SYMBOL(drm_fb_helper_pan_display);
675 757
676int drm_fb_helper_single_fb_probe(struct drm_device *dev, 758int drm_fb_helper_single_fb_probe(struct drm_device *dev,
759 int preferred_bpp,
677 int (*fb_create)(struct drm_device *dev, 760 int (*fb_create)(struct drm_device *dev,
678 uint32_t fb_width, 761 uint32_t fb_width,
679 uint32_t fb_height, 762 uint32_t fb_height,
@@ -696,6 +779,11 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
696 struct drm_fb_helper *fb_helper; 779 struct drm_fb_helper *fb_helper;
697 uint32_t surface_depth = 24, surface_bpp = 32; 780 uint32_t surface_depth = 24, surface_bpp = 32;
698 781
782 /* if driver picks 8 or 16 by default use that
783 for both depth/bpp */
784 if (preferred_bpp != surface_bpp) {
785 surface_depth = surface_bpp = preferred_bpp;
786 }
699 /* first up get a count of crtcs now in use and new min/maxes width/heights */ 787 /* first up get a count of crtcs now in use and new min/maxes width/heights */
700 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 788 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
701 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; 789 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
@@ -851,10 +939,12 @@ void drm_fb_helper_free(struct drm_fb_helper *helper)
851} 939}
852EXPORT_SYMBOL(drm_fb_helper_free); 940EXPORT_SYMBOL(drm_fb_helper_free);
853 941
854void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch) 942void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
943 uint32_t depth)
855{ 944{
856 info->fix.type = FB_TYPE_PACKED_PIXELS; 945 info->fix.type = FB_TYPE_PACKED_PIXELS;
857 info->fix.visual = FB_VISUAL_TRUECOLOR; 946 info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
947 FB_VISUAL_TRUECOLOR;
858 info->fix.type_aux = 0; 948 info->fix.type_aux = 0;
859 info->fix.xpanstep = 1; /* doing it in hw */ 949 info->fix.xpanstep = 1; /* doing it in hw */
860 info->fix.ypanstep = 1; /* doing it in hw */ 950 info->fix.ypanstep = 1; /* doing it in hw */