diff options
Diffstat (limited to 'drivers/gpu/drm/drm_fb_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 154 |
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 | } |
455 | EXPORT_SYMBOL(drm_fb_helper_init_crtc_count); | 455 | EXPORT_SYMBOL(drm_fb_helper_init_crtc_count); |
456 | 456 | ||
457 | static 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 | |||
516 | int 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 | } | ||
558 | EXPORT_SYMBOL(drm_fb_helper_setcmap); | ||
559 | |||
457 | int drm_fb_helper_setcolreg(unsigned regno, | 560 | int 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, | |||
674 | EXPORT_SYMBOL(drm_fb_helper_pan_display); | 756 | EXPORT_SYMBOL(drm_fb_helper_pan_display); |
675 | 757 | ||
676 | int drm_fb_helper_single_fb_probe(struct drm_device *dev, | 758 | int 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 | } |
852 | EXPORT_SYMBOL(drm_fb_helper_free); | 940 | EXPORT_SYMBOL(drm_fb_helper_free); |
853 | 941 | ||
854 | void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch) | 942 | void 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 */ |