Commit 37f9003b authored by Alex Deucher's avatar Alex Deucher Committed by Dave Airlie

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: default avatarAlex Deucher <alexdeucher@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 90c1efdd
...@@ -669,56 +669,25 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc) ...@@ -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); 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 drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
struct drm_encoder *encoder = NULL;
struct radeon_encoder *radeon_encoder = NULL;
u8 frev, crev; u8 frev, crev;
int index; int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
union set_pixel_clock args; 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)); 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, if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
&crev)) &crev))
return; return;
...@@ -727,47 +696,49 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode ...@@ -727,47 +696,49 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
case 1: case 1:
switch (crev) { switch (crev) {
case 1: 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.usRefDiv = cpu_to_le16(ref_div);
args.v1.usFbDiv = cpu_to_le16(fb_div); args.v1.usFbDiv = cpu_to_le16(fb_div);
args.v1.ucFracFbDiv = frac_fb_div; args.v1.ucFracFbDiv = frac_fb_div;
args.v1.ucPostDiv = post_div; args.v1.ucPostDiv = post_div;
args.v1.ucPpll = radeon_crtc->pll_id; args.v1.ucPpll = pll_id;
args.v1.ucCRTC = radeon_crtc->crtc_id; args.v1.ucCRTC = crtc_id;
args.v1.ucRefDivSrc = 1; args.v1.ucRefDivSrc = 1;
break; break;
case 2: 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.usRefDiv = cpu_to_le16(ref_div);
args.v2.usFbDiv = cpu_to_le16(fb_div); args.v2.usFbDiv = cpu_to_le16(fb_div);
args.v2.ucFracFbDiv = frac_fb_div; args.v2.ucFracFbDiv = frac_fb_div;
args.v2.ucPostDiv = post_div; args.v2.ucPostDiv = post_div;
args.v2.ucPpll = radeon_crtc->pll_id; args.v2.ucPpll = pll_id;
args.v2.ucCRTC = radeon_crtc->crtc_id; args.v2.ucCRTC = crtc_id;
args.v2.ucRefDivSrc = 1; args.v2.ucRefDivSrc = 1;
break; break;
case 3: 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.usRefDiv = cpu_to_le16(ref_div);
args.v3.usFbDiv = cpu_to_le16(fb_div); args.v3.usFbDiv = cpu_to_le16(fb_div);
args.v3.ucFracFbDiv = frac_fb_div; args.v3.ucFracFbDiv = frac_fb_div;
args.v3.ucPostDiv = post_div; args.v3.ucPostDiv = post_div;
args.v3.ucPpll = radeon_crtc->pll_id; args.v3.ucPpll = pll_id;
args.v3.ucMiscInfo = (radeon_crtc->pll_id << 2); args.v3.ucMiscInfo = (pll_id << 2);
args.v3.ucTransmitterId = radeon_encoder->encoder_id; args.v3.ucTransmitterId = encoder_id;
args.v3.ucEncoderMode = encoder_mode; args.v3.ucEncoderMode = encoder_mode;
break; break;
case 5: case 5:
args.v5.ucCRTC = radeon_crtc->crtc_id; args.v5.ucCRTC = crtc_id;
args.v5.usPixelClock = cpu_to_le16(mode->clock / 10); args.v5.usPixelClock = cpu_to_le16(clock / 10);
args.v5.ucRefDiv = ref_div; args.v5.ucRefDiv = ref_div;
args.v5.usFbDiv = cpu_to_le16(fb_div); args.v5.usFbDiv = cpu_to_le16(fb_div);
args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
args.v5.ucPostDiv = post_div; args.v5.ucPostDiv = post_div;
args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 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.ucEncoderMode = encoder_mode;
args.v5.ucPpll = radeon_crtc->pll_id; args.v5.ucPpll = pll_id;
break; break;
default: default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev); 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,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); 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, static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb) struct drm_framebuffer *old_fb)
{ {
...@@ -1191,6 +1212,24 @@ static void atombios_crtc_commit(struct drm_crtc *crtc) ...@@ -1191,6 +1212,24 @@ static void atombios_crtc_commit(struct drm_crtc *crtc)
atombios_lock_crtc(crtc, ATOM_DISABLE); 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 = { static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
.dpms = atombios_crtc_dpms, .dpms = atombios_crtc_dpms,
.mode_fixup = atombios_crtc_mode_fixup, .mode_fixup = atombios_crtc_mode_fixup,
...@@ -1199,6 +1238,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = { ...@@ -1199,6 +1238,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
.prepare = atombios_crtc_prepare, .prepare = atombios_crtc_prepare,
.commit = atombios_crtc_commit, .commit = atombios_crtc_commit,
.load_lut = radeon_crtc_load_lut, .load_lut = radeon_crtc_load_lut,
.disable = atombios_crtc_disable,
}; };
void radeon_atombios_init_crtc(struct drm_device *dev, void radeon_atombios_init_crtc(struct drm_device *dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment