/* * Copyright 2007-8 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Dave Airlie * Alex Deucher
*/
staticvoid atombios_crtc_program_ss(struct radeon_device *rdev, int enable, int pll_id, int crtc_id, struct radeon_atom_ss *ss)
{ unsigned i; int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); union atom_enable_ss args;
if (enable) { /* Don't mess with SS if percentage is 0 or external ss. * SS is already disabled previously, and disabling it * again can cause display problems if the pll is already * programmed.
*/ if (ss->percentage == 0) return; if (ss->type & ATOM_EXTERNAL_SS_MASK) return;
} else { for (i = 0; i < rdev->num_crtc; i++) { if (rdev->mode_info.crtcs[i] &&
rdev->mode_info.crtcs[i]->enabled &&
i != crtc_id &&
pll_id == rdev->mode_info.crtcs[i]->pll_id) { /* one other crtc is using this pll don't turn * off spread spectrum as it might turn off * display on active crtc
*/ return;
}
}
}
/* use recommended ref_div for ss */ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (radeon_crtc->ss_enabled) { if (radeon_crtc->ss.refdiv) {
radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;
radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv; if (ASIC_IS_AVIVO(rdev) &&
rdev->family != CHIP_RS780 &&
rdev->family != CHIP_RS880)
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
}
}
}
if (ASIC_IS_AVIVO(rdev)) { /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
adjusted_clock = mode->clock * 2; if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD;
} else { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)
radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;
}
/* adjust pll for deep color modes */ if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { switch (bpc) { case 8: default: break; case 10:
clock = (clock * 5) / 4; break; case 12:
clock = (clock * 3) / 2; break; case 16:
clock = clock * 2; break;
}
}
/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock * accordingly based on the encoder/transmitter to work around * special hw requirements.
*/ if (ASIC_IS_DCE3(rdev)) { union adjust_pixel_clock args;
u8 frev, crev; int index;
index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
&crev)) return adjusted_clock;
memset(&args, 0, sizeof(args));
switch (frev) { case 1: switch (crev) { case 1: case 2:
args.v1.usPixelClock = cpu_to_le16(clock / 10);
args.v1.ucTransmitterID = radeon_encoder->encoder_id;
args.v1.ucEncodeMode = encoder_mode; if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage)
args.v1.ucConfig |=
ADJUST_DISPLAY_CONFIG_SS_ENABLE;
/* on DCE5, make sure the voltage is high enough to support the * required disp clk.
*/ staticvoid atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev,
u32 dispclk)
{
u8 frev, crev; int index; union set_pixel_clock args;
memset(&args, 0, sizeof(args));
index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
&crev)) return;
switch (frev) { case 1: switch (crev) { case 5: /* if the default dcpll clock is specified, * SetPixelClock provides the dividers
*/
args.v5.ucCRTC = ATOM_CRTC_INVALID;
args.v5.usPixelClock = cpu_to_le16(dispclk);
args.v5.ucPpll = ATOM_DCPLL; break; case 6: /* if the default dcpll clock is specified, * SetPixelClock provides the dividers
*/
args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); if (ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev))
args.v6.ucPpll = ATOM_EXT_PLL1; elseif (ASIC_IS_DCE6(rdev))
args.v6.ucPpll = ATOM_PPLL0; else
args.v6.ucPpll = ATOM_DCPLL; break; default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev); return;
} break; default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev); return;
}
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args));
}
/* Assign mode clock for hdmi deep color max clock limit check */
radeon_connector->pixelclock_for_modeset = mode->clock;
radeon_crtc->bpc = radeon_get_monitor_bpc(connector);
switch (encoder_mode) { case ATOM_ENCODER_MODE_DP_MST: case ATOM_ENCODER_MODE_DP: /* DP/eDP */
dp_clock = dig_connector->dp_clock / 10; if (ASIC_IS_DCE4(rdev))
radeon_crtc->ss_enabled =
radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss,
ASIC_INTERNAL_SS_ON_DP,
dp_clock); else { if (dp_clock == 16200) {
radeon_crtc->ss_enabled =
radeon_atombios_get_ppll_ss_info(rdev,
&radeon_crtc->ss,
ATOM_DP_SS_ID2); if (!radeon_crtc->ss_enabled)
radeon_crtc->ss_enabled =
radeon_atombios_get_ppll_ss_info(rdev,
&radeon_crtc->ss,
ATOM_DP_SS_ID1);
} else {
radeon_crtc->ss_enabled =
radeon_atombios_get_ppll_ss_info(rdev,
&radeon_crtc->ss,
ATOM_DP_SS_ID1);
} /* disable spread spectrum on DCE3 DP */
radeon_crtc->ss_enabled = false;
} break; case ATOM_ENCODER_MODE_LVDS: if (ASIC_IS_DCE4(rdev))
radeon_crtc->ss_enabled =
radeon_atombios_get_asic_ss_info(rdev,
&radeon_crtc->ss,
dig->lcd_ss_id,
mode->clock / 10); else
radeon_crtc->ss_enabled =
radeon_atombios_get_ppll_ss_info(rdev,
&radeon_crtc->ss,
dig->lcd_ss_id); break; case ATOM_ENCODER_MODE_DVI: if (ASIC_IS_DCE4(rdev))
radeon_crtc->ss_enabled =
radeon_atombios_get_asic_ss_info(rdev,
&radeon_crtc->ss,
ASIC_INTERNAL_SS_ON_TMDS,
mode->clock / 10); break; case ATOM_ENCODER_MODE_HDMI: if (ASIC_IS_DCE4(rdev))
radeon_crtc->ss_enabled =
radeon_atombios_get_asic_ss_info(rdev,
&radeon_crtc->ss,
ASIC_INTERNAL_SS_ON_HDMI,
mode->clock / 10); break; default: break;
}
}
/* pass the actual clock to atombios_crtc_program_pll for DCE5,6 for HDMI */ if (ASIC_IS_DCE5(rdev) &&
(encoder_mode == ATOM_ENCODER_MODE_HDMI) &&
(radeon_crtc->bpc > 8))
clock = radeon_crtc->adjusted_clock;
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;
}
/* no fb bound */ if (!atomic && !crtc->primary->fb) {
DRM_DEBUG_KMS("No FB bound\n"); return 0;
}
if (atomic)
target_fb = fb; else
target_fb = crtc->primary->fb;
/* If atomic, assume fb object is pinned & idle & fenced and * just update base pointers
*/
obj = target_fb->obj[0];
rbo = gem_to_radeon_bo(obj);
r = radeon_bo_reserve(rbo, false); if (unlikely(r != 0)) return r;
if (atomic)
fb_location = radeon_bo_gpu_offset(rbo); else {
r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); if (unlikely(r != 0)) {
radeon_bo_unreserve(rbo); return -EINVAL;
}
}
fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1);
fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split);
fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);
fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh);
fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect); if (rdev->family >= CHIP_BONAIRE) { /* XXX need to know more about the surface tiling mode */
fb_format |= CIK_GRPH_MICRO_TILE_MODE(CIK_DISPLAY_MICRO_TILING);
}
} elseif (tiling_flags & RADEON_TILING_MICRO)
fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
if (rdev->family >= CHIP_BONAIRE) { /* Read the pipe config from the 2D TILED SCANOUT mode. * It should be the same for the other modes too, but not all
* modes set the pipe config field. */
u32 pipe_config = (rdev->config.cik.tile_mode_array[10] >> 6) & 0x1f;
switch (radeon_crtc->crtc_id) { case 0:
WREG32(AVIVO_D1VGA_CONTROL, 0); break; case 1:
WREG32(AVIVO_D2VGA_CONTROL, 0); break; case 2:
WREG32(EVERGREEN_D3VGA_CONTROL, 0); break; case 3:
WREG32(EVERGREEN_D4VGA_CONTROL, 0); break; case 4:
WREG32(EVERGREEN_D5VGA_CONTROL, 0); break; case 5:
WREG32(EVERGREEN_D6VGA_CONTROL, 0); break; default: break;
}
/* Make sure surface address is updated at vertical blank rather than * horizontal blank
*/
WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0);
/* * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to * retain the full precision throughout the pipeline.
*/
WREG32_P(EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL + radeon_crtc->crtc_offset,
(bypass_lut ? EVERGREEN_LUT_10BIT_BYPASS_EN : 0),
~EVERGREEN_LUT_10BIT_BYPASS_EN);
if (bypass_lut)
DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n");
/* no fb bound */ if (!atomic && !crtc->primary->fb) {
DRM_DEBUG_KMS("No FB bound\n"); return 0;
}
if (atomic)
target_fb = fb; else
target_fb = crtc->primary->fb;
obj = target_fb->obj[0];
rbo = gem_to_radeon_bo(obj);
r = radeon_bo_reserve(rbo, false); if (unlikely(r != 0)) return r;
/* If atomic, assume fb object is pinned & idle & fenced and * just update base pointers
*/ if (atomic)
fb_location = radeon_bo_gpu_offset(rbo); else {
r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); if (unlikely(r != 0)) {
radeon_bo_unreserve(rbo); return -EINVAL;
}
}
radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
radeon_bo_unreserve(rbo);
switch (target_fb->format->format) { case DRM_FORMAT_C8:
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |
AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; break; case DRM_FORMAT_XRGB4444: case DRM_FORMAT_ARGB4444:
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444; #ifdef __BIG_ENDIAN
fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; #endif break; case DRM_FORMAT_XRGB1555:
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; #ifdef __BIG_ENDIAN
fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; #endif break; case DRM_FORMAT_RGB565:
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
AVIVO_D1GRPH_CONTROL_16BPP_RGB565; #ifdef __BIG_ENDIAN
fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; #endif break; case DRM_FORMAT_XRGB8888: case DRM_FORMAT_ARGB8888:
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; #ifdef __BIG_ENDIAN
fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; #endif break; case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_ARGB2101010:
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010; #ifdef __BIG_ENDIAN
fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; #endif /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
bypass_lut = true; break; case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ABGR8888:
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; if (rdev->family >= CHIP_R600)
fb_swap =
(R600_D1GRPH_RED_CROSSBAR(R600_D1GRPH_RED_SEL_B) |
R600_D1GRPH_BLUE_CROSSBAR(R600_D1GRPH_BLUE_SEL_R)); else/* DCE1 (R5xx) */
fb_format |= AVIVO_D1GRPH_SWAP_RB; #ifdef __BIG_ENDIAN
fb_swap |= R600_D1GRPH_SWAP_ENDIAN_32BIT; #endif break; default:
DRM_ERROR("Unsupported screen format %p4cc\n",
&target_fb->format->format); return -EINVAL;
}
if (rdev->family >= CHIP_R600) { if (tiling_flags & RADEON_TILING_MACRO)
fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; elseif (tiling_flags & RADEON_TILING_MICRO)
fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1;
} else { if (tiling_flags & RADEON_TILING_MACRO)
fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
if (tiling_flags & RADEON_TILING_MICRO)
fb_format |= AVIVO_D1GRPH_TILED;
}
if (radeon_crtc->crtc_id == 0)
WREG32(AVIVO_D1VGA_CONTROL, 0); else
WREG32(AVIVO_D2VGA_CONTROL, 0);
/* Make sure surface address is update at vertical blank rather than * horizontal blank
*/
WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0);
/** * radeon_get_pll_use_mask - look up a mask of which pplls are in use * * @crtc: drm crtc * * Returns the mask of which PPLLs (Pixel PLLs) are in use.
*/ static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc)
{ struct drm_device *dev = crtc->dev; struct drm_crtc *test_crtc; struct radeon_crtc *test_radeon_crtc;
u32 pll_in_use = 0;
list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { if (crtc == test_crtc) continue;
/** * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP * * @crtc: drm crtc * * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is * also in DP mode. For DP, a single PPLL can be used for all DP * crtcs/encoders.
*/ staticint radeon_get_shared_dp_ppll(struct drm_crtc *crtc)
{ struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct drm_crtc *test_crtc; struct radeon_crtc *test_radeon_crtc;
list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { if (crtc == test_crtc) continue;
test_radeon_crtc = to_radeon_crtc(test_crtc); if (test_radeon_crtc->encoder &&
ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { /* PPLL2 is exclusive to UNIPHYA on DCE61 */ if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) &&
test_radeon_crtc->pll_id == ATOM_PPLL2) continue; /* for DP use the same PLL for all */ if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) return test_radeon_crtc->pll_id;
}
} return ATOM_PPLL_INVALID;
}
/** * radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc * * @crtc: drm crtc * * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can * be shared (i.e., same clock).
*/ staticint radeon_get_shared_nondp_ppll(struct drm_crtc *crtc)
{ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct drm_crtc *test_crtc; struct radeon_crtc *test_radeon_crtc;
u32 adjusted_clock, test_adjusted_clock;
adjusted_clock = radeon_crtc->adjusted_clock;
if (adjusted_clock == 0) return ATOM_PPLL_INVALID;
list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { if (crtc == test_crtc) continue;
test_radeon_crtc = to_radeon_crtc(test_crtc); if (test_radeon_crtc->encoder &&
!ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { /* PPLL2 is exclusive to UNIPHYA on DCE61 */ if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) &&
test_radeon_crtc->pll_id == ATOM_PPLL2) continue; /* check if we are already driving this connector with another crtc */ if (test_radeon_crtc->connector == radeon_crtc->connector) { /* if we are, return that pll */ if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) return test_radeon_crtc->pll_id;
} /* for non-DP check the clock */
test_adjusted_clock = test_radeon_crtc->adjusted_clock; if ((crtc->mode.clock == test_crtc->mode.clock) &&
(adjusted_clock == test_adjusted_clock) &&
(radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) &&
(test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) return test_radeon_crtc->pll_id;
}
} return ATOM_PPLL_INVALID;
}
/** * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. * * @crtc: drm crtc * * Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors * a single PPLL can be used for all DP crtcs/encoders. For non-DP * monitors a dedicated PPLL must be used. If a particular board has * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming * as there is no need to program the PLL itself. If we are not able to * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to * avoid messing up an existing monitor. * * Asic specific PLL information * * DCE 8.x * KB/KV * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) * CI * - PPLL0, PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC * * DCE 6.1 * - PPLL2 is only available to UNIPHYA (both DP and non-DP) * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) * * DCE 6.0 * - PPLL0 is available to all UNIPHY (DP only) * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC * * DCE 5.0 * - DCPLL is available to all UNIPHY (DP only) * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC * * DCE 3.0/4.0/4.1 * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC *
*/ staticint radeon_atom_pick_pll(struct drm_crtc *crtc)
{ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder =
to_radeon_encoder(radeon_crtc->encoder);
u32 pll_in_use; int pll;
if (ASIC_IS_DCE8(rdev)) { if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { if (rdev->clock.dp_extclk) /* skip PPLL programming if using ext clock */ return ATOM_PPLL_INVALID; else { /* use the same PPLL for all DP monitors */
pll = radeon_get_shared_dp_ppll(crtc); if (pll != ATOM_PPLL_INVALID) return pll;
}
} else { /* use the same PPLL for all monitors with the same clock */
pll = radeon_get_shared_nondp_ppll(crtc); if (pll != ATOM_PPLL_INVALID) return pll;
} /* otherwise, pick one of the plls */ if ((rdev->family == CHIP_KABINI) ||
(rdev->family == CHIP_MULLINS)) { /* KB/ML has PPLL1 and PPLL2 */
pll_in_use = radeon_get_pll_use_mask(crtc); if (!(pll_in_use & (1 << ATOM_PPLL2))) return ATOM_PPLL2; if (!(pll_in_use & (1 << ATOM_PPLL1))) return ATOM_PPLL1;
DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID;
} else { /* CI/KV has PPLL0, PPLL1, and PPLL2 */
pll_in_use = radeon_get_pll_use_mask(crtc); if (!(pll_in_use & (1 << ATOM_PPLL2))) return ATOM_PPLL2; if (!(pll_in_use & (1 << ATOM_PPLL1))) return ATOM_PPLL1; if (!(pll_in_use & (1 << ATOM_PPLL0))) return ATOM_PPLL0;
DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID;
}
} elseif (ASIC_IS_DCE61(rdev)) { struct radeon_encoder_atom_dig *dig =
radeon_encoder->enc_priv;
if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY) &&
(dig->linkb == false)) /* UNIPHY A uses PPLL2 */ return ATOM_PPLL2; elseif (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { /* UNIPHY B/C/D/E/F */ if (rdev->clock.dp_extclk) /* skip PPLL programming if using ext clock */ return ATOM_PPLL_INVALID; else { /* use the same PPLL for all DP monitors */
pll = radeon_get_shared_dp_ppll(crtc); if (pll != ATOM_PPLL_INVALID) return pll;
}
} else { /* use the same PPLL for all monitors with the same clock */
pll = radeon_get_shared_nondp_ppll(crtc); if (pll != ATOM_PPLL_INVALID) return pll;
} /* UNIPHY B/C/D/E/F */
pll_in_use = radeon_get_pll_use_mask(crtc); if (!(pll_in_use & (1 << ATOM_PPLL0))) return ATOM_PPLL0; if (!(pll_in_use & (1 << ATOM_PPLL1))) return ATOM_PPLL1;
DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID;
} elseif (ASIC_IS_DCE41(rdev)) { /* Don't share PLLs on DCE4.1 chips */ if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { if (rdev->clock.dp_extclk) /* skip PPLL programming if using ext clock */ return ATOM_PPLL_INVALID;
}
pll_in_use = radeon_get_pll_use_mask(crtc); if (!(pll_in_use & (1 << ATOM_PPLL1))) return ATOM_PPLL1; if (!(pll_in_use & (1 << ATOM_PPLL2))) return ATOM_PPLL2;
DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID;
} elseif (ASIC_IS_DCE4(rdev)) { /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, * depending on the asic: * DCE4: PPLL or ext clock * DCE5: PPLL, DCPLL, or ext clock * DCE6: PPLL, PPLL0, or ext clock * * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip * PPLL/DCPLL programming and only program the DP DTO for the * crtc virtual pixel clock.
*/ if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { if (rdev->clock.dp_extclk) /* skip PPLL programming if using ext clock */ return ATOM_PPLL_INVALID; elseif (ASIC_IS_DCE6(rdev)) /* use PPLL0 for all DP */ return ATOM_PPLL0; elseif (ASIC_IS_DCE5(rdev)) /* use DCPLL for all DP */ return ATOM_DCPLL; else { /* use the same PPLL for all DP monitors */
pll = radeon_get_shared_dp_ppll(crtc); if (pll != ATOM_PPLL_INVALID) return pll;
}
} else { /* use the same PPLL for all monitors with the same clock */
pll = radeon_get_shared_nondp_ppll(crtc); if (pll != ATOM_PPLL_INVALID) return pll;
} /* all other cases */
pll_in_use = radeon_get_pll_use_mask(crtc); if (!(pll_in_use & (1 << ATOM_PPLL1))) return ATOM_PPLL1; if (!(pll_in_use & (1 << ATOM_PPLL2))) return ATOM_PPLL2;
DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID;
} else { /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ /* some atombios (observed in some DCE2/DCE3) code have a bug, * the matching btw pll and crtc is done through * PCLK_CRTC[1|2]_CNTL (0x480/0x484) but atombios code use the * pll (1 or 2) to select which register to write. ie if using * pll1 it will use PCLK_CRTC1_CNTL (0x480) and if using pll2 * it will use PCLK_CRTC2_CNTL (0x484), it then use crtc id to * choose which value to write. Which is reverse order from
--> --------------------
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.