diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2010-06-11 17:58:38 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-07-20 21:27:21 -0400 |
commit | 37f9003bd355d9109769fff66f7f228aab42155b (patch) | |
tree | f25cfac28c99937596a5a6fcdcaebe076a589c71 /drivers/gpu/drm | |
parent | 90c1efdd121c84ee73e9960667229a662f2315a3 (diff) |
drm/radeon/kms/atom: add crtc disable function
Disables the crts as per dpms and also disables the ppll
associated with the crtc. This should save additional power.
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_crtc.c | 152 |
1 files changed, 96 insertions, 56 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 8c2d6478a221..a22d5a3bca4e 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
@@ -669,56 +669,25 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc) | |||
669 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | 669 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
670 | } | 670 | } |
671 | 671 | ||
672 | static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) | 672 | static void atombios_crtc_program_pll(struct drm_crtc *crtc, |
673 | int crtc_id, | ||
674 | int pll_id, | ||
675 | u32 encoder_mode, | ||
676 | u32 encoder_id, | ||
677 | u32 clock, | ||
678 | u32 ref_div, | ||
679 | u32 fb_div, | ||
680 | u32 frac_fb_div, | ||
681 | u32 post_div) | ||
673 | { | 682 | { |
674 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
675 | struct drm_device *dev = crtc->dev; | 683 | struct drm_device *dev = crtc->dev; |
676 | struct radeon_device *rdev = dev->dev_private; | 684 | struct radeon_device *rdev = dev->dev_private; |
677 | struct drm_encoder *encoder = NULL; | ||
678 | struct radeon_encoder *radeon_encoder = NULL; | ||
679 | u8 frev, crev; | 685 | u8 frev, crev; |
680 | int index; | 686 | int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); |
681 | union set_pixel_clock args; | 687 | union set_pixel_clock args; |
682 | u32 pll_clock = mode->clock; | ||
683 | u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; | ||
684 | struct radeon_pll *pll; | ||
685 | u32 adjusted_clock; | ||
686 | int encoder_mode = 0; | ||
687 | 688 | ||
688 | memset(&args, 0, sizeof(args)); | 689 | memset(&args, 0, sizeof(args)); |
689 | 690 | ||
690 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
691 | if (encoder->crtc == crtc) { | ||
692 | radeon_encoder = to_radeon_encoder(encoder); | ||
693 | encoder_mode = atombios_get_encoder_mode(encoder); | ||
694 | break; | ||
695 | } | ||
696 | } | ||
697 | |||
698 | if (!radeon_encoder) | ||
699 | return; | ||
700 | |||
701 | switch (radeon_crtc->pll_id) { | ||
702 | case ATOM_PPLL1: | ||
703 | pll = &rdev->clock.p1pll; | ||
704 | break; | ||
705 | case ATOM_PPLL2: | ||
706 | pll = &rdev->clock.p2pll; | ||
707 | break; | ||
708 | case ATOM_DCPLL: | ||
709 | case ATOM_PPLL_INVALID: | ||
710 | default: | ||
711 | pll = &rdev->clock.dcpll; | ||
712 | break; | ||
713 | } | ||
714 | |||
715 | /* adjust pixel clock as needed */ | ||
716 | adjusted_clock = atombios_adjust_pll(crtc, mode, pll); | ||
717 | |||
718 | radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, | ||
719 | &ref_div, &post_div); | ||
720 | |||
721 | index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); | ||
722 | if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, | 691 | if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, |
723 | &crev)) | 692 | &crev)) |
724 | return; | 693 | return; |
@@ -727,47 +696,49 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode | |||
727 | case 1: | 696 | case 1: |
728 | switch (crev) { | 697 | switch (crev) { |
729 | case 1: | 698 | case 1: |
730 | args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); | 699 | if (clock == ATOM_DISABLE) |
700 | return; | ||
701 | args.v1.usPixelClock = cpu_to_le16(clock / 10); | ||
731 | args.v1.usRefDiv = cpu_to_le16(ref_div); | 702 | args.v1.usRefDiv = cpu_to_le16(ref_div); |
732 | args.v1.usFbDiv = cpu_to_le16(fb_div); | 703 | args.v1.usFbDiv = cpu_to_le16(fb_div); |
733 | args.v1.ucFracFbDiv = frac_fb_div; | 704 | args.v1.ucFracFbDiv = frac_fb_div; |
734 | args.v1.ucPostDiv = post_div; | 705 | args.v1.ucPostDiv = post_div; |
735 | args.v1.ucPpll = radeon_crtc->pll_id; | 706 | args.v1.ucPpll = pll_id; |
736 | args.v1.ucCRTC = radeon_crtc->crtc_id; | 707 | args.v1.ucCRTC = crtc_id; |
737 | args.v1.ucRefDivSrc = 1; | 708 | args.v1.ucRefDivSrc = 1; |
738 | break; | 709 | break; |
739 | case 2: | 710 | case 2: |
740 | args.v2.usPixelClock = cpu_to_le16(mode->clock / 10); | 711 | args.v2.usPixelClock = cpu_to_le16(clock / 10); |
741 | args.v2.usRefDiv = cpu_to_le16(ref_div); | 712 | args.v2.usRefDiv = cpu_to_le16(ref_div); |
742 | args.v2.usFbDiv = cpu_to_le16(fb_div); | 713 | args.v2.usFbDiv = cpu_to_le16(fb_div); |
743 | args.v2.ucFracFbDiv = frac_fb_div; | 714 | args.v2.ucFracFbDiv = frac_fb_div; |
744 | args.v2.ucPostDiv = post_div; | 715 | args.v2.ucPostDiv = post_div; |
745 | args.v2.ucPpll = radeon_crtc->pll_id; | 716 | args.v2.ucPpll = pll_id; |
746 | args.v2.ucCRTC = radeon_crtc->crtc_id; | 717 | args.v2.ucCRTC = crtc_id; |
747 | args.v2.ucRefDivSrc = 1; | 718 | args.v2.ucRefDivSrc = 1; |
748 | break; | 719 | break; |
749 | case 3: | 720 | case 3: |
750 | args.v3.usPixelClock = cpu_to_le16(mode->clock / 10); | 721 | args.v3.usPixelClock = cpu_to_le16(clock / 10); |
751 | args.v3.usRefDiv = cpu_to_le16(ref_div); | 722 | args.v3.usRefDiv = cpu_to_le16(ref_div); |
752 | args.v3.usFbDiv = cpu_to_le16(fb_div); | 723 | args.v3.usFbDiv = cpu_to_le16(fb_div); |
753 | args.v3.ucFracFbDiv = frac_fb_div; | 724 | args.v3.ucFracFbDiv = frac_fb_div; |
754 | args.v3.ucPostDiv = post_div; | 725 | args.v3.ucPostDiv = post_div; |
755 | args.v3.ucPpll = radeon_crtc->pll_id; | 726 | args.v3.ucPpll = pll_id; |
756 | args.v3.ucMiscInfo = (radeon_crtc->pll_id << 2); | 727 | args.v3.ucMiscInfo = (pll_id << 2); |
757 | args.v3.ucTransmitterId = radeon_encoder->encoder_id; | 728 | args.v3.ucTransmitterId = encoder_id; |
758 | args.v3.ucEncoderMode = encoder_mode; | 729 | args.v3.ucEncoderMode = encoder_mode; |
759 | break; | 730 | break; |
760 | case 5: | 731 | case 5: |
761 | args.v5.ucCRTC = radeon_crtc->crtc_id; | 732 | args.v5.ucCRTC = crtc_id; |
762 | args.v5.usPixelClock = cpu_to_le16(mode->clock / 10); | 733 | args.v5.usPixelClock = cpu_to_le16(clock / 10); |
763 | args.v5.ucRefDiv = ref_div; | 734 | args.v5.ucRefDiv = ref_div; |
764 | args.v5.usFbDiv = cpu_to_le16(fb_div); | 735 | args.v5.usFbDiv = cpu_to_le16(fb_div); |
765 | args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); | 736 | args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); |
766 | args.v5.ucPostDiv = post_div; | 737 | args.v5.ucPostDiv = post_div; |
767 | args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ | 738 | args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ |
768 | args.v5.ucTransmitterID = radeon_encoder->encoder_id; | 739 | args.v5.ucTransmitterID = encoder_id; |
769 | args.v5.ucEncoderMode = encoder_mode; | 740 | args.v5.ucEncoderMode = encoder_mode; |
770 | args.v5.ucPpll = radeon_crtc->pll_id; | 741 | args.v5.ucPpll = pll_id; |
771 | break; | 742 | break; |
772 | default: | 743 | default: |
773 | DRM_ERROR("Unknown table version %d %d\n", frev, crev); | 744 | DRM_ERROR("Unknown table version %d %d\n", frev, crev); |
@@ -782,6 +753,56 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode | |||
782 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | 753 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
783 | } | 754 | } |
784 | 755 | ||
756 | static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) | ||
757 | { | ||
758 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
759 | struct drm_device *dev = crtc->dev; | ||
760 | struct radeon_device *rdev = dev->dev_private; | ||
761 | struct drm_encoder *encoder = NULL; | ||
762 | struct radeon_encoder *radeon_encoder = NULL; | ||
763 | u32 pll_clock = mode->clock; | ||
764 | u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; | ||
765 | struct radeon_pll *pll; | ||
766 | u32 adjusted_clock; | ||
767 | int encoder_mode = 0; | ||
768 | |||
769 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
770 | if (encoder->crtc == crtc) { | ||
771 | radeon_encoder = to_radeon_encoder(encoder); | ||
772 | encoder_mode = atombios_get_encoder_mode(encoder); | ||
773 | break; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | if (!radeon_encoder) | ||
778 | return; | ||
779 | |||
780 | switch (radeon_crtc->pll_id) { | ||
781 | case ATOM_PPLL1: | ||
782 | pll = &rdev->clock.p1pll; | ||
783 | break; | ||
784 | case ATOM_PPLL2: | ||
785 | pll = &rdev->clock.p2pll; | ||
786 | break; | ||
787 | case ATOM_DCPLL: | ||
788 | case ATOM_PPLL_INVALID: | ||
789 | default: | ||
790 | pll = &rdev->clock.dcpll; | ||
791 | break; | ||
792 | } | ||
793 | |||
794 | /* adjust pixel clock as needed */ | ||
795 | adjusted_clock = atombios_adjust_pll(crtc, mode, pll); | ||
796 | |||
797 | radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, | ||
798 | &ref_div, &post_div); | ||
799 | |||
800 | atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, | ||
801 | encoder_mode, radeon_encoder->encoder_id, mode->clock, | ||
802 | ref_div, fb_div, frac_fb_div, post_div); | ||
803 | |||
804 | } | ||
805 | |||
785 | static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, | 806 | static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
786 | struct drm_framebuffer *old_fb) | 807 | struct drm_framebuffer *old_fb) |
787 | { | 808 | { |
@@ -1191,6 +1212,24 @@ static void atombios_crtc_commit(struct drm_crtc *crtc) | |||
1191 | atombios_lock_crtc(crtc, ATOM_DISABLE); | 1212 | atombios_lock_crtc(crtc, ATOM_DISABLE); |
1192 | } | 1213 | } |
1193 | 1214 | ||
1215 | static void atombios_crtc_disable(struct drm_crtc *crtc) | ||
1216 | { | ||
1217 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
1218 | atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | ||
1219 | |||
1220 | switch (radeon_crtc->pll_id) { | ||
1221 | case ATOM_PPLL1: | ||
1222 | case ATOM_PPLL2: | ||
1223 | /* disable the ppll */ | ||
1224 | atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, | ||
1225 | 0, 0, ATOM_DISABLE, 0, 0, 0, 0); | ||
1226 | break; | ||
1227 | default: | ||
1228 | break; | ||
1229 | } | ||
1230 | radeon_crtc->pll_id = -1; | ||
1231 | } | ||
1232 | |||
1194 | static const struct drm_crtc_helper_funcs atombios_helper_funcs = { | 1233 | static const struct drm_crtc_helper_funcs atombios_helper_funcs = { |
1195 | .dpms = atombios_crtc_dpms, | 1234 | .dpms = atombios_crtc_dpms, |
1196 | .mode_fixup = atombios_crtc_mode_fixup, | 1235 | .mode_fixup = atombios_crtc_mode_fixup, |
@@ -1199,6 +1238,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = { | |||
1199 | .prepare = atombios_crtc_prepare, | 1238 | .prepare = atombios_crtc_prepare, |
1200 | .commit = atombios_crtc_commit, | 1239 | .commit = atombios_crtc_commit, |
1201 | .load_lut = radeon_crtc_load_lut, | 1240 | .load_lut = radeon_crtc_load_lut, |
1241 | .disable = atombios_crtc_disable, | ||
1202 | }; | 1242 | }; |
1203 | 1243 | ||
1204 | void radeon_atombios_init_crtc(struct drm_device *dev, | 1244 | void radeon_atombios_init_crtc(struct drm_device *dev, |