Skip to content

Commit 0fbe321

Browse files
Timur Kristófalexdeucher
authored andcommitted
drm/amd/display: Implement DCE analog link encoders (v2)
We support two kinds of analog connections: 1. DVI-I, which allows both digital and analog signals: The DC code base only allows 1 encoder per connector, and the preferred engine type is still going to be digital. So, for DVI-I to work, we need to make sure the pre-existing link encoder can also work with analog signals. 1. VGA, which only supports analog signals: For VGA, we need to create a link encoder that only works with the DAC without perturbing any digital transmitter functionality. Since dce110_link_encoder already supports analog DVI-I, just reuse that code for VGA as well. v2: Reduce code churn by reusing same link encoder for VGA and DVI-I. Signed-off-by: Timur Kristóf <timur.kristof@gmail.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1 parent deb072d commit 0fbe321

5 files changed

Lines changed: 141 additions & 11 deletions

File tree

drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ static void setup_panel_mode(
302302
if (ctx->dc->caps.psp_setup_panel_mode)
303303
return;
304304

305+
/* The code below is only applicable to encoders with a digital transmitter. */
306+
if (enc110->base.transmitter == TRANSMITTER_UNKNOWN)
307+
return;
308+
305309
ASSERT(REG(DP_DPHY_INTERNAL_CTRL));
306310
value = REG_READ(DP_DPHY_INTERNAL_CTRL);
307311

@@ -804,6 +808,33 @@ bool dce110_link_encoder_validate_dp_output(
804808
return true;
805809
}
806810

811+
static bool dce110_link_encoder_validate_rgb_output(
812+
const struct dce110_link_encoder *enc110,
813+
const struct dc_crtc_timing *crtc_timing)
814+
{
815+
/* When the VBIOS doesn't specify any limits, use 400 MHz.
816+
* The value comes from amdgpu_atombios_get_clock_info.
817+
*/
818+
uint32_t max_pixel_clock_khz = 400000;
819+
820+
if (enc110->base.ctx->dc_bios->fw_info_valid &&
821+
enc110->base.ctx->dc_bios->fw_info.max_pixel_clock) {
822+
max_pixel_clock_khz =
823+
enc110->base.ctx->dc_bios->fw_info.max_pixel_clock;
824+
}
825+
826+
if (crtc_timing->pix_clk_100hz > max_pixel_clock_khz * 10)
827+
return false;
828+
829+
if (crtc_timing->display_color_depth != COLOR_DEPTH_888)
830+
return false;
831+
832+
if (crtc_timing->pixel_encoding != PIXEL_ENCODING_RGB)
833+
return false;
834+
835+
return true;
836+
}
837+
807838
void dce110_link_encoder_construct(
808839
struct dce110_link_encoder *enc110,
809840
const struct encoder_init_data *init_data,
@@ -824,6 +855,7 @@ void dce110_link_encoder_construct(
824855
enc110->base.connector = init_data->connector;
825856

826857
enc110->base.preferred_engine = ENGINE_ID_UNKNOWN;
858+
enc110->base.analog_engine = init_data->analog_engine;
827859

828860
enc110->base.features = *enc_features;
829861

@@ -847,6 +879,11 @@ void dce110_link_encoder_construct(
847879
SIGNAL_TYPE_EDP |
848880
SIGNAL_TYPE_HDMI_TYPE_A;
849881

882+
if ((enc110->base.connector.id == CONNECTOR_ID_DUAL_LINK_DVII ||
883+
enc110->base.connector.id == CONNECTOR_ID_SINGLE_LINK_DVII) &&
884+
enc110->base.analog_engine != ENGINE_ID_UNKNOWN)
885+
enc110->base.output_signals |= SIGNAL_TYPE_RGB;
886+
850887
/* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE.
851888
* SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY.
852889
* SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer
@@ -885,6 +922,13 @@ void dce110_link_encoder_construct(
885922
enc110->base.preferred_engine = ENGINE_ID_DIGG;
886923
break;
887924
default:
925+
if (init_data->analog_engine != ENGINE_ID_UNKNOWN) {
926+
/* The connector is analog-only, ie. VGA */
927+
enc110->base.preferred_engine = init_data->analog_engine;
928+
enc110->base.output_signals = SIGNAL_TYPE_RGB;
929+
enc110->base.transmitter = TRANSMITTER_UNKNOWN;
930+
break;
931+
}
888932
ASSERT_CRITICAL(false);
889933
enc110->base.preferred_engine = ENGINE_ID_UNKNOWN;
890934
}
@@ -939,6 +983,10 @@ bool dce110_link_encoder_validate_output_with_stream(
939983
is_valid = dce110_link_encoder_validate_dp_output(
940984
enc110, &stream->timing);
941985
break;
986+
case SIGNAL_TYPE_RGB:
987+
is_valid = dce110_link_encoder_validate_rgb_output(
988+
enc110, &stream->timing);
989+
break;
942990
case SIGNAL_TYPE_EDP:
943991
case SIGNAL_TYPE_LVDS:
944992
is_valid = stream->timing.pixel_encoding == PIXEL_ENCODING_RGB;
@@ -969,6 +1017,10 @@ void dce110_link_encoder_hw_init(
9691017
cntl.coherent = false;
9701018
cntl.hpd_sel = enc110->base.hpd_source;
9711019

1020+
/* The code below is only applicable to encoders with a digital transmitter. */
1021+
if (enc110->base.transmitter == TRANSMITTER_UNKNOWN)
1022+
return;
1023+
9721024
if (enc110->base.connector.id == CONNECTOR_ID_EDP)
9731025
cntl.signal = SIGNAL_TYPE_EDP;
9741026

@@ -1034,6 +1086,8 @@ void dce110_link_encoder_setup(
10341086
/* DP MST */
10351087
REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 5);
10361088
break;
1089+
case SIGNAL_TYPE_RGB:
1090+
break;
10371091
default:
10381092
ASSERT_CRITICAL(false);
10391093
/* invalid mode ! */
@@ -1282,6 +1336,24 @@ void dce110_link_encoder_disable_output(
12821336
struct bp_transmitter_control cntl = { 0 };
12831337
enum bp_result result;
12841338

1339+
switch (enc->analog_engine) {
1340+
case ENGINE_ID_DACA:
1341+
REG_UPDATE(DAC_ENABLE, DAC_ENABLE, 0);
1342+
break;
1343+
case ENGINE_ID_DACB:
1344+
/* DACB doesn't seem to be present on DCE6+,
1345+
* although there are references to it in the register file.
1346+
*/
1347+
DC_LOG_ERROR("%s DACB is unsupported\n", __func__);
1348+
break;
1349+
default:
1350+
break;
1351+
}
1352+
1353+
/* The code below only applies to connectors that support digital signals. */
1354+
if (enc->transmitter == TRANSMITTER_UNKNOWN)
1355+
return;
1356+
12851357
if (!dce110_is_dig_enabled(enc)) {
12861358
/* OF_SKIP_POWER_DOWN_INACTIVE_ENCODER */
12871359
return;
@@ -1726,6 +1798,7 @@ void dce60_link_encoder_construct(
17261798
enc110->base.connector = init_data->connector;
17271799

17281800
enc110->base.preferred_engine = ENGINE_ID_UNKNOWN;
1801+
enc110->base.analog_engine = init_data->analog_engine;
17291802

17301803
enc110->base.features = *enc_features;
17311804

@@ -1749,6 +1822,11 @@ void dce60_link_encoder_construct(
17491822
SIGNAL_TYPE_EDP |
17501823
SIGNAL_TYPE_HDMI_TYPE_A;
17511824

1825+
if ((enc110->base.connector.id == CONNECTOR_ID_DUAL_LINK_DVII ||
1826+
enc110->base.connector.id == CONNECTOR_ID_SINGLE_LINK_DVII) &&
1827+
enc110->base.analog_engine != ENGINE_ID_UNKNOWN)
1828+
enc110->base.output_signals |= SIGNAL_TYPE_RGB;
1829+
17521830
/* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE.
17531831
* SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY.
17541832
* SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer
@@ -1787,6 +1865,13 @@ void dce60_link_encoder_construct(
17871865
enc110->base.preferred_engine = ENGINE_ID_DIGG;
17881866
break;
17891867
default:
1868+
if (init_data->analog_engine != ENGINE_ID_UNKNOWN) {
1869+
/* The connector is analog-only, ie. VGA */
1870+
enc110->base.preferred_engine = init_data->analog_engine;
1871+
enc110->base.output_signals = SIGNAL_TYPE_RGB;
1872+
enc110->base.transmitter = TRANSMITTER_UNKNOWN;
1873+
break;
1874+
}
17901875
ASSERT_CRITICAL(false);
17911876
enc110->base.preferred_engine = ENGINE_ID_UNKNOWN;
17921877
}

drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,18 +101,21 @@
101101
SRI(DP_SEC_CNTL, DP, id), \
102102
SRI(DP_VID_STREAM_CNTL, DP, id), \
103103
SRI(DP_DPHY_FAST_TRAINING, DP, id), \
104-
SRI(DP_SEC_CNTL1, DP, id)
104+
SRI(DP_SEC_CNTL1, DP, id), \
105+
SR(DAC_ENABLE)
105106
#endif
106107

107108
#define LE_DCE80_REG_LIST(id)\
108109
SRI(DP_DPHY_INTERNAL_CTRL, DP, id), \
109-
LE_COMMON_REG_LIST_BASE(id)
110+
LE_COMMON_REG_LIST_BASE(id), \
111+
SR(DAC_ENABLE)
110112

111113
#define LE_DCE100_REG_LIST(id)\
112114
LE_COMMON_REG_LIST_BASE(id), \
113115
SRI(DP_DPHY_BS_SR_SWAP_CNTL, DP, id), \
114116
SRI(DP_DPHY_INTERNAL_CTRL, DP, id), \
115-
SR(DCI_MEM_PWR_STATUS)
117+
SR(DCI_MEM_PWR_STATUS), \
118+
SR(DAC_ENABLE)
116119

117120
#define LE_DCE110_REG_LIST(id)\
118121
LE_COMMON_REG_LIST_BASE(id), \
@@ -181,6 +184,9 @@ struct dce110_link_enc_registers {
181184
uint32_t DP_DPHY_BS_SR_SWAP_CNTL;
182185
uint32_t DP_DPHY_HBR2_PATTERN_CONTROL;
183186
uint32_t DP_SEC_CNTL1;
187+
188+
/* DAC registers */
189+
uint32_t DAC_ENABLE;
184190
};
185191

186192
struct dce110_link_encoder {
@@ -215,10 +221,6 @@ bool dce110_link_encoder_validate_dvi_output(
215221
enum signal_type signal,
216222
const struct dc_crtc_timing *crtc_timing);
217223

218-
bool dce110_link_encoder_validate_rgb_output(
219-
const struct dce110_link_encoder *enc110,
220-
const struct dc_crtc_timing *crtc_timing);
221-
222224
bool dce110_link_encoder_validate_dp_output(
223225
const struct dce110_link_encoder *enc110,
224226
const struct dc_crtc_timing *crtc_timing);

drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ static const struct dce110_link_enc_registers link_enc_regs[] = {
225225
link_regs(4),
226226
link_regs(5),
227227
link_regs(6),
228+
{ .DAC_ENABLE = mmDAC_ENABLE },
228229
};
229230

230231
#define stream_enc_regs(id)\
@@ -632,7 +633,20 @@ static struct link_encoder *dce100_link_encoder_create(
632633
kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL);
633634
int link_regs_id;
634635

635-
if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
636+
if (!enc110)
637+
return NULL;
638+
639+
if (enc_init_data->connector.id == CONNECTOR_ID_VGA) {
640+
dce110_link_encoder_construct(enc110,
641+
enc_init_data,
642+
&link_enc_feature,
643+
&link_enc_regs[ENGINE_ID_DACA],
644+
NULL,
645+
NULL);
646+
return &enc110->base;
647+
}
648+
649+
if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
636650
return NULL;
637651

638652
link_regs_id =

drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,9 @@ static const struct dce110_link_enc_registers link_enc_regs[] = {
240240
link_regs(2),
241241
link_regs(3),
242242
link_regs(4),
243-
link_regs(5)
243+
link_regs(5),
244+
{0},
245+
{ .DAC_ENABLE = mmDAC_ENABLE },
244246
};
245247

246248
#define stream_enc_regs(id)\
@@ -726,7 +728,20 @@ static struct link_encoder *dce60_link_encoder_create(
726728
kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL);
727729
int link_regs_id;
728730

729-
if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
731+
if (!enc110)
732+
return NULL;
733+
734+
if (enc_init_data->connector.id == CONNECTOR_ID_VGA) {
735+
dce110_link_encoder_construct(enc110,
736+
enc_init_data,
737+
&link_enc_feature,
738+
&link_enc_regs[ENGINE_ID_DACA],
739+
NULL,
740+
NULL);
741+
return &enc110->base;
742+
}
743+
744+
if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
730745
return NULL;
731746

732747
link_regs_id =

drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ static const struct dce110_link_enc_registers link_enc_regs[] = {
241241
link_regs(4),
242242
link_regs(5),
243243
link_regs(6),
244+
{ .DAC_ENABLE = mmDAC_ENABLE },
244245
};
245246

246247
#define stream_enc_regs(id)\
@@ -734,7 +735,20 @@ static struct link_encoder *dce80_link_encoder_create(
734735
kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL);
735736
int link_regs_id;
736737

737-
if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
738+
if (!enc110)
739+
return NULL;
740+
741+
if (enc_init_data->connector.id == CONNECTOR_ID_VGA) {
742+
dce110_link_encoder_construct(enc110,
743+
enc_init_data,
744+
&link_enc_feature,
745+
&link_enc_regs[ENGINE_ID_DACA],
746+
NULL,
747+
NULL);
748+
return &enc110->base;
749+
}
750+
751+
if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
738752
return NULL;
739753

740754
link_regs_id =

0 commit comments

Comments
 (0)