Skip to content

Commit 82d3543

Browse files
Satheeshakrishna Mdanvet
authored andcommitted
drm/i915/skl: Implementation of SKL DPLL programming
This patch implements SKL DPLL programming that includes: - DPLL allocation - wide range PLL calculation and programming - DP link rate programming - DDI to DPLL mapping v2: Incorporated following changes - Added vfunc for function required outside - Fixed multiple comments in WRPLL calculation v3: - Fix the DCO computation - Move the initialization up to not clobber the computed values - Use the correct macro for DP link rate programming. - Use wait_for() to wait for the PLL locked bit v4: Rebase on top of nigthly (Damien) v5: A few code cleanups in the WRPLL computation (Damien) - Use uint32_t when possible - Use abs_diff() in the WRPLL computation - Make the 64bits divisions use div64_u64() - Fix typo in dco_central_feq_deviation (freq) - Replace the chain of breaks with a goto v6: Port of the patch to work on top of the shared DPLLs (Damien) v7: Don't try to handle eDP in ddi_pll_select() (Damien) v8: Modified as per review comments from Paulo (Satheesh) v9: Rebase on top of Ander's clock computation staging work for atomic (Damien) Reviewed-by: Paulo Zanoni <[email protected]> Signed-off-by: Satheeshakrishna M <[email protected]> (v3) Signed-off-by: Damien Lespiau <[email protected]> Signed-off-by: Daniel Vetter <[email protected]>
1 parent efa80ad commit 82d3543

File tree

1 file changed

+225
-1
lines changed

1 file changed

+225
-1
lines changed

drivers/gpu/drm/i915/intel_ddi.c

Lines changed: 225 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,226 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
937937
return true;
938938
}
939939

940+
struct skl_wrpll_params {
941+
uint32_t dco_fraction;
942+
uint32_t dco_integer;
943+
uint32_t qdiv_ratio;
944+
uint32_t qdiv_mode;
945+
uint32_t kdiv;
946+
uint32_t pdiv;
947+
uint32_t central_freq;
948+
};
949+
950+
static void
951+
skl_ddi_calculate_wrpll(int clock /* in Hz */,
952+
struct skl_wrpll_params *wrpll_params)
953+
{
954+
uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
955+
uint64_t dco_central_freq[3] = {8400000000, 9000000000, 9600000000};
956+
uint32_t min_dco_deviation = 400;
957+
uint32_t min_dco_index = 3;
958+
uint32_t P0[4] = {1, 2, 3, 7};
959+
uint32_t P2[4] = {1, 2, 3, 5};
960+
bool found = false;
961+
uint32_t candidate_p = 0;
962+
uint32_t candidate_p0[3] = {0}, candidate_p1[3] = {0};
963+
uint32_t candidate_p2[3] = {0};
964+
uint32_t dco_central_freq_deviation[3];
965+
uint32_t i, P1, k, dco_count;
966+
bool retry_with_odd = false;
967+
uint64_t dco_freq;
968+
969+
/* Determine P0, P1 or P2 */
970+
for (dco_count = 0; dco_count < 3; dco_count++) {
971+
found = false;
972+
candidate_p =
973+
div64_u64(dco_central_freq[dco_count], afe_clock);
974+
if (retry_with_odd == false)
975+
candidate_p = (candidate_p % 2 == 0 ?
976+
candidate_p : candidate_p + 1);
977+
978+
for (P1 = 1; P1 < candidate_p; P1++) {
979+
for (i = 0; i < 4; i++) {
980+
if (!(P0[i] != 1 || P1 == 1))
981+
continue;
982+
983+
for (k = 0; k < 4; k++) {
984+
if (P1 != 1 && P2[k] != 2)
985+
continue;
986+
987+
if (candidate_p == P0[i] * P1 * P2[k]) {
988+
/* Found possible P0, P1, P2 */
989+
found = true;
990+
candidate_p0[dco_count] = P0[i];
991+
candidate_p1[dco_count] = P1;
992+
candidate_p2[dco_count] = P2[k];
993+
goto found;
994+
}
995+
996+
}
997+
}
998+
}
999+
1000+
found:
1001+
if (found) {
1002+
dco_central_freq_deviation[dco_count] =
1003+
div64_u64(10000 *
1004+
abs_diff((candidate_p * afe_clock),
1005+
dco_central_freq[dco_count]),
1006+
dco_central_freq[dco_count]);
1007+
1008+
if (dco_central_freq_deviation[dco_count] <
1009+
min_dco_deviation) {
1010+
min_dco_deviation =
1011+
dco_central_freq_deviation[dco_count];
1012+
min_dco_index = dco_count;
1013+
}
1014+
}
1015+
1016+
if (min_dco_index > 2 && dco_count == 2) {
1017+
retry_with_odd = true;
1018+
dco_count = 0;
1019+
}
1020+
}
1021+
1022+
if (min_dco_index > 2) {
1023+
WARN(1, "No valid values found for the given pixel clock\n");
1024+
} else {
1025+
wrpll_params->central_freq = dco_central_freq[min_dco_index];
1026+
1027+
switch (dco_central_freq[min_dco_index]) {
1028+
case 9600000000:
1029+
wrpll_params->central_freq = 0;
1030+
break;
1031+
case 9000000000:
1032+
wrpll_params->central_freq = 1;
1033+
break;
1034+
case 8400000000:
1035+
wrpll_params->central_freq = 3;
1036+
}
1037+
1038+
switch (candidate_p0[min_dco_index]) {
1039+
case 1:
1040+
wrpll_params->pdiv = 0;
1041+
break;
1042+
case 2:
1043+
wrpll_params->pdiv = 1;
1044+
break;
1045+
case 3:
1046+
wrpll_params->pdiv = 2;
1047+
break;
1048+
case 7:
1049+
wrpll_params->pdiv = 4;
1050+
break;
1051+
default:
1052+
WARN(1, "Incorrect PDiv\n");
1053+
}
1054+
1055+
switch (candidate_p2[min_dco_index]) {
1056+
case 5:
1057+
wrpll_params->kdiv = 0;
1058+
break;
1059+
case 2:
1060+
wrpll_params->kdiv = 1;
1061+
break;
1062+
case 3:
1063+
wrpll_params->kdiv = 2;
1064+
break;
1065+
case 1:
1066+
wrpll_params->kdiv = 3;
1067+
break;
1068+
default:
1069+
WARN(1, "Incorrect KDiv\n");
1070+
}
1071+
1072+
wrpll_params->qdiv_ratio = candidate_p1[min_dco_index];
1073+
wrpll_params->qdiv_mode =
1074+
(wrpll_params->qdiv_ratio == 1) ? 0 : 1;
1075+
1076+
dco_freq = candidate_p0[min_dco_index] *
1077+
candidate_p1[min_dco_index] *
1078+
candidate_p2[min_dco_index] * afe_clock;
1079+
1080+
/*
1081+
* Intermediate values are in Hz.
1082+
* Divide by MHz to match bsepc
1083+
*/
1084+
wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1)));
1085+
wrpll_params->dco_fraction =
1086+
div_u64(((div_u64(dco_freq, 24) -
1087+
wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1));
1088+
1089+
}
1090+
}
1091+
1092+
1093+
static bool
1094+
skl_ddi_pll_select(struct intel_crtc *intel_crtc,
1095+
struct intel_encoder *intel_encoder,
1096+
int clock)
1097+
{
1098+
struct intel_shared_dpll *pll;
1099+
uint32_t ctrl1, cfgcr1, cfgcr2;
1100+
1101+
/*
1102+
* See comment in intel_dpll_hw_state to understand why we always use 0
1103+
* as the DPLL id in this function.
1104+
*/
1105+
1106+
ctrl1 = DPLL_CTRL1_OVERRIDE(0);
1107+
1108+
if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
1109+
struct skl_wrpll_params wrpll_params = { 0, };
1110+
1111+
ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
1112+
1113+
skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params);
1114+
1115+
cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
1116+
DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
1117+
wrpll_params.dco_integer;
1118+
1119+
cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
1120+
DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
1121+
DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
1122+
DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
1123+
wrpll_params.central_freq;
1124+
} else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
1125+
struct drm_encoder *encoder = &intel_encoder->base;
1126+
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
1127+
1128+
switch (intel_dp->link_bw) {
1129+
case DP_LINK_BW_1_62:
1130+
ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_810, 0);
1131+
break;
1132+
case DP_LINK_BW_2_7:
1133+
ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1350, 0);
1134+
break;
1135+
case DP_LINK_BW_5_4:
1136+
ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2700, 0);
1137+
break;
1138+
}
1139+
1140+
cfgcr1 = cfgcr2 = 0;
1141+
} else /* eDP */
1142+
return true;
1143+
1144+
intel_crtc->new_config->dpll_hw_state.ctrl1 = ctrl1;
1145+
intel_crtc->new_config->dpll_hw_state.cfgcr1 = cfgcr1;
1146+
intel_crtc->new_config->dpll_hw_state.cfgcr2 = cfgcr2;
1147+
1148+
pll = intel_get_shared_dpll(intel_crtc);
1149+
if (pll == NULL) {
1150+
DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
1151+
pipe_name(intel_crtc->pipe));
1152+
return false;
1153+
}
1154+
1155+
/* shared DPLL id 0 is DPLL 1 */
1156+
intel_crtc->new_config->ddi_pll_sel = pll->id + 1;
1157+
1158+
return true;
1159+
}
9401160

9411161
/*
9421162
* Tries to find a *shared* PLL for the CRTC and store it in
@@ -947,11 +1167,15 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
9471167
*/
9481168
bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
9491169
{
1170+
struct drm_device *dev = intel_crtc->base.dev;
9501171
struct intel_encoder *intel_encoder =
9511172
intel_ddi_get_crtc_new_encoder(intel_crtc);
9521173
int clock = intel_crtc->new_config->port_clock;
9531174

954-
return hsw_ddi_pll_select(intel_crtc, intel_encoder, clock);
1175+
if (IS_SKYLAKE(dev))
1176+
return skl_ddi_pll_select(intel_crtc, intel_encoder, clock);
1177+
else
1178+
return hsw_ddi_pll_select(intel_crtc, intel_encoder, clock);
9551179
}
9561180

9571181
void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)

0 commit comments

Comments
 (0)