More explicit than dpms. Same as the encoder disable function.
Signed-off-by: Alex Deucher alexdeucher@gmail.com --- drivers/gpu/drm/drm_crtc_helper.c | 5 ++++- include/drm/drm_crtc_helper.h | 3 +++ 2 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 9b2a541..fa1323f 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -241,7 +241,10 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; crtc->enabled = drm_helper_crtc_in_use(crtc); if (!crtc->enabled) { - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); + if (crtc_funcs->disable) + (*crtc_funcs->disable)(crtc); + else + (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF); crtc->fb = NULL; } } diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 1121f77..7e3c976 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -63,6 +63,9 @@ struct drm_crtc_helper_funcs {
/* reload the current crtc LUT */ void (*load_lut)(struct drm_crtc *crtc); + + /* disable crtc when not in use - more explicit than dpms off */ + void (*disable)(struct drm_crtc *crtc); };
struct drm_encoder_helper_funcs {
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 --- 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 8c2d647..a22d5a3 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) atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); }
-static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) +static void atombios_crtc_program_pll(struct drm_crtc *crtc, + int crtc_id, + int pll_id, + u32 encoder_mode, + u32 encoder_id, + u32 clock, + u32 ref_div, + u32 fb_div, + u32 frac_fb_div, + u32 post_div) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; - struct drm_encoder *encoder = NULL; - struct radeon_encoder *radeon_encoder = NULL; u8 frev, crev; - int index; + int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); union set_pixel_clock args; - u32 pll_clock = mode->clock; - u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; - struct radeon_pll *pll; - u32 adjusted_clock; - int encoder_mode = 0;
memset(&args, 0, sizeof(args));
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - radeon_encoder = to_radeon_encoder(encoder); - encoder_mode = atombios_get_encoder_mode(encoder); - break; - } - } - - if (!radeon_encoder) - return; - - switch (radeon_crtc->pll_id) { - case ATOM_PPLL1: - pll = &rdev->clock.p1pll; - break; - case ATOM_PPLL2: - pll = &rdev->clock.p2pll; - break; - case ATOM_DCPLL: - case ATOM_PPLL_INVALID: - default: - pll = &rdev->clock.dcpll; - break; - } - - /* adjust pixel clock as needed */ - adjusted_clock = atombios_adjust_pll(crtc, mode, pll); - - radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div); - - index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) return; @@ -727,47 +696,49 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode case 1: switch (crev) { case 1: - args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); + if (clock == ATOM_DISABLE) + return; + args.v1.usPixelClock = cpu_to_le16(clock / 10); args.v1.usRefDiv = cpu_to_le16(ref_div); args.v1.usFbDiv = cpu_to_le16(fb_div); args.v1.ucFracFbDiv = frac_fb_div; args.v1.ucPostDiv = post_div; - args.v1.ucPpll = radeon_crtc->pll_id; - args.v1.ucCRTC = radeon_crtc->crtc_id; + args.v1.ucPpll = pll_id; + args.v1.ucCRTC = crtc_id; args.v1.ucRefDivSrc = 1; break; case 2: - args.v2.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v2.usPixelClock = cpu_to_le16(clock / 10); args.v2.usRefDiv = cpu_to_le16(ref_div); args.v2.usFbDiv = cpu_to_le16(fb_div); args.v2.ucFracFbDiv = frac_fb_div; args.v2.ucPostDiv = post_div; - args.v2.ucPpll = radeon_crtc->pll_id; - args.v2.ucCRTC = radeon_crtc->crtc_id; + args.v2.ucPpll = pll_id; + args.v2.ucCRTC = crtc_id; args.v2.ucRefDivSrc = 1; break; case 3: - args.v3.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v3.usPixelClock = cpu_to_le16(clock / 10); args.v3.usRefDiv = cpu_to_le16(ref_div); args.v3.usFbDiv = cpu_to_le16(fb_div); args.v3.ucFracFbDiv = frac_fb_div; args.v3.ucPostDiv = post_div; - args.v3.ucPpll = radeon_crtc->pll_id; - args.v3.ucMiscInfo = (radeon_crtc->pll_id << 2); - args.v3.ucTransmitterId = radeon_encoder->encoder_id; + args.v3.ucPpll = pll_id; + args.v3.ucMiscInfo = (pll_id << 2); + args.v3.ucTransmitterId = encoder_id; args.v3.ucEncoderMode = encoder_mode; break; case 5: - args.v5.ucCRTC = radeon_crtc->crtc_id; - args.v5.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v5.ucCRTC = crtc_id; + args.v5.usPixelClock = cpu_to_le16(clock / 10); args.v5.ucRefDiv = ref_div; args.v5.usFbDiv = cpu_to_le16(fb_div); args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); args.v5.ucPostDiv = post_div; args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ - args.v5.ucTransmitterID = radeon_encoder->encoder_id; + args.v5.ucTransmitterID = encoder_id; args.v5.ucEncoderMode = encoder_mode; - args.v5.ucPpll = radeon_crtc->pll_id; + args.v5.ucPpll = pll_id; break; default: 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 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); }
+static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder = NULL; + struct radeon_encoder *radeon_encoder = NULL; + u32 pll_clock = mode->clock; + u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; + struct radeon_pll *pll; + u32 adjusted_clock; + int encoder_mode = 0; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + radeon_encoder = to_radeon_encoder(encoder); + encoder_mode = atombios_get_encoder_mode(encoder); + break; + } + } + + if (!radeon_encoder) + return; + + switch (radeon_crtc->pll_id) { + case ATOM_PPLL1: + pll = &rdev->clock.p1pll; + break; + case ATOM_PPLL2: + pll = &rdev->clock.p2pll; + break; + case ATOM_DCPLL: + case ATOM_PPLL_INVALID: + default: + pll = &rdev->clock.dcpll; + break; + } + + /* adjust pixel clock as needed */ + adjusted_clock = atombios_adjust_pll(crtc, mode, pll); + + radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, + &ref_div, &post_div); + + atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, + encoder_mode, radeon_encoder->encoder_id, mode->clock, + ref_div, fb_div, frac_fb_div, post_div); + +} + static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { @@ -1191,6 +1212,24 @@ static void atombios_crtc_commit(struct drm_crtc *crtc) atombios_lock_crtc(crtc, ATOM_DISABLE); }
+static void atombios_crtc_disable(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + + switch (radeon_crtc->pll_id) { + case ATOM_PPLL1: + case ATOM_PPLL2: + /* disable the ppll */ + atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, + 0, 0, ATOM_DISABLE, 0, 0, 0, 0); + break; + default: + break; + } + radeon_crtc->pll_id = -1; +} + static const struct drm_crtc_helper_funcs atombios_helper_funcs = { .dpms = atombios_crtc_dpms, .mode_fixup = atombios_crtc_mode_fixup, @@ -1199,6 +1238,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = { .prepare = atombios_crtc_prepare, .commit = atombios_crtc_commit, .load_lut = radeon_crtc_load_lut, + .disable = atombios_crtc_disable, };
void radeon_atombios_init_crtc(struct drm_device *dev,
On Fri, 11 Jun 2010 18:00:09 -0400, Alex Deucher alexdeucher@gmail.com wrote:
Disables the crts as per dpms and also disables the ppll associated with the crtc. This should save additional power.
Any reason the pll isn't just disabled for dpms as well?
On Fri, Jun 11, 2010 at 6:34 PM, Keith Packard keithp@keithp.com wrote:
On Fri, 11 Jun 2010 18:00:09 -0400, Alex Deucher alexdeucher@gmail.com wrote:
Disables the crts as per dpms and also disables the ppll associated with the crtc. This should save additional power.
Any reason the pll isn't just disabled for dpms as well?
No, it could be. I had originally done that when I was experimenting with disabling the ppll. I just means resetting the ppll in the dpms code.
Alex
dri-devel@lists.freedesktop.org