diff options
Diffstat (limited to 'drivers/gpu/drm/drm_fb_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 138 |
1 files changed, 106 insertions, 32 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 819ddcbfcce5..23dc9c115fd9 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -454,6 +454,96 @@ 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 void 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 | pindex = regno; | ||
465 | |||
466 | if (fb->bits_per_pixel == 16) { | ||
467 | pindex = regno << 3; | ||
468 | |||
469 | if (fb->depth == 16 && regno > 63) | ||
470 | return; | ||
471 | if (fb->depth == 15 && regno > 31) | ||
472 | return; | ||
473 | |||
474 | if (fb->depth == 16) { | ||
475 | u16 r, g, b; | ||
476 | int i; | ||
477 | if (regno < 32) { | ||
478 | for (i = 0; i < 8; i++) | ||
479 | fb_helper->funcs->gamma_set(crtc, red, | ||
480 | green, blue, pindex + i); | ||
481 | } | ||
482 | |||
483 | fb_helper->funcs->gamma_get(crtc, &r, | ||
484 | &g, &b, | ||
485 | pindex >> 1); | ||
486 | |||
487 | for (i = 0; i < 4; i++) | ||
488 | fb_helper->funcs->gamma_set(crtc, r, | ||
489 | green, b, | ||
490 | (pindex >> 1) + i); | ||
491 | } | ||
492 | } | ||
493 | |||
494 | if (fb->depth != 16) | ||
495 | fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex); | ||
496 | |||
497 | if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { | ||
498 | ((u32 *) fb->pseudo_palette)[regno] = | ||
499 | (regno << info->var.red.offset) | | ||
500 | (regno << info->var.green.offset) | | ||
501 | (regno << info->var.blue.offset); | ||
502 | } | ||
503 | } | ||
504 | |||
505 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) | ||
506 | { | ||
507 | struct drm_fb_helper *fb_helper = info->par; | ||
508 | struct drm_device *dev = fb_helper->dev; | ||
509 | u16 *red, *green, *blue, *transp; | ||
510 | struct drm_crtc *crtc; | ||
511 | int i, rc = 0; | ||
512 | int start; | ||
513 | |||
514 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
515 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
516 | for (i = 0; i < fb_helper->crtc_count; i++) { | ||
517 | if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) | ||
518 | break; | ||
519 | } | ||
520 | if (i == fb_helper->crtc_count) | ||
521 | continue; | ||
522 | |||
523 | red = cmap->red; | ||
524 | green = cmap->green; | ||
525 | blue = cmap->blue; | ||
526 | transp = cmap->transp; | ||
527 | start = cmap->start; | ||
528 | |||
529 | for (i = 0; i < cmap->len; i++) { | ||
530 | u16 hred, hgreen, hblue, htransp = 0xffff; | ||
531 | |||
532 | hred = *red++; | ||
533 | hgreen = *green++; | ||
534 | hblue = *blue++; | ||
535 | |||
536 | if (transp) | ||
537 | htransp = *transp++; | ||
538 | |||
539 | setcolreg(crtc, hred, hgreen, hblue, start++, info); | ||
540 | } | ||
541 | crtc_funcs->load_lut(crtc); | ||
542 | } | ||
543 | return rc; | ||
544 | } | ||
545 | EXPORT_SYMBOL(drm_fb_helper_setcmap); | ||
546 | |||
457 | int drm_fb_helper_setcolreg(unsigned regno, | 547 | int drm_fb_helper_setcolreg(unsigned regno, |
458 | unsigned red, | 548 | unsigned red, |
459 | unsigned green, | 549 | unsigned green, |
@@ -466,9 +556,11 @@ int drm_fb_helper_setcolreg(unsigned regno, | |||
466 | struct drm_crtc *crtc; | 556 | struct drm_crtc *crtc; |
467 | int i; | 557 | int i; |
468 | 558 | ||
469 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 559 | if (regno > 255) |
470 | struct drm_framebuffer *fb = fb_helper->fb; | 560 | return 1; |
471 | 561 | ||
562 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
563 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
472 | for (i = 0; i < fb_helper->crtc_count; i++) { | 564 | for (i = 0; i < fb_helper->crtc_count; i++) { |
473 | if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) | 565 | if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) |
474 | break; | 566 | break; |
@@ -476,35 +568,9 @@ int drm_fb_helper_setcolreg(unsigned regno, | |||
476 | if (i == fb_helper->crtc_count) | 568 | if (i == fb_helper->crtc_count) |
477 | continue; | 569 | continue; |
478 | 570 | ||
479 | if (regno > 255) | ||
480 | return 1; | ||
481 | |||
482 | if (fb->depth == 8) { | ||
483 | fb_helper->funcs->gamma_set(crtc, red, green, blue, regno); | ||
484 | return 0; | ||
485 | } | ||
486 | 571 | ||
487 | if (regno < 16) { | 572 | setcolreg(crtc, red, green, blue, regno, info); |
488 | switch (fb->depth) { | 573 | crtc_funcs->load_lut(crtc); |
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 | } | 574 | } |
509 | return 0; | 575 | return 0; |
510 | } | 576 | } |
@@ -674,6 +740,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, | |||
674 | EXPORT_SYMBOL(drm_fb_helper_pan_display); | 740 | EXPORT_SYMBOL(drm_fb_helper_pan_display); |
675 | 741 | ||
676 | int drm_fb_helper_single_fb_probe(struct drm_device *dev, | 742 | int drm_fb_helper_single_fb_probe(struct drm_device *dev, |
743 | int preferred_bpp, | ||
677 | int (*fb_create)(struct drm_device *dev, | 744 | int (*fb_create)(struct drm_device *dev, |
678 | uint32_t fb_width, | 745 | uint32_t fb_width, |
679 | uint32_t fb_height, | 746 | uint32_t fb_height, |
@@ -696,6 +763,11 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, | |||
696 | struct drm_fb_helper *fb_helper; | 763 | struct drm_fb_helper *fb_helper; |
697 | uint32_t surface_depth = 24, surface_bpp = 32; | 764 | uint32_t surface_depth = 24, surface_bpp = 32; |
698 | 765 | ||
766 | /* if driver picks 8 or 16 by default use that | ||
767 | for both depth/bpp */ | ||
768 | if (preferred_bpp != surface_bpp) { | ||
769 | surface_depth = surface_bpp = preferred_bpp; | ||
770 | } | ||
699 | /* first up get a count of crtcs now in use and new min/maxes width/heights */ | 771 | /* 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) { | 772 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
701 | struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; | 773 | struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; |
@@ -851,10 +923,12 @@ void drm_fb_helper_free(struct drm_fb_helper *helper) | |||
851 | } | 923 | } |
852 | EXPORT_SYMBOL(drm_fb_helper_free); | 924 | EXPORT_SYMBOL(drm_fb_helper_free); |
853 | 925 | ||
854 | void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch) | 926 | void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, |
927 | uint32_t depth) | ||
855 | { | 928 | { |
856 | info->fix.type = FB_TYPE_PACKED_PIXELS; | 929 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
857 | info->fix.visual = FB_VISUAL_TRUECOLOR; | 930 | info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : |
931 | FB_VISUAL_DIRECTCOLOR; | ||
858 | info->fix.type_aux = 0; | 932 | info->fix.type_aux = 0; |
859 | info->fix.xpanstep = 1; /* doing it in hw */ | 933 | info->fix.xpanstep = 1; /* doing it in hw */ |
860 | info->fix.ypanstep = 1; /* doing it in hw */ | 934 | info->fix.ypanstep = 1; /* doing it in hw */ |