]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
drm/amd/dc: Add dc display driver (v2)
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / amd / display / dc / core / dc_link_hwss.c
1 /* Copyright 2015 Advanced Micro Devices, Inc. */
2
3
4 #include "dm_services.h"
5 #include "dc.h"
6 #include "inc/core_dc.h"
7 #include "include/ddc_service_types.h"
8 #include "include/i2caux_interface.h"
9 #include "link_hwss.h"
10 #include "hw_sequencer.h"
11 #include "dc_link_dp.h"
12 #include "dc_link_ddc.h"
13 #include "dm_helpers.h"
14 #include "dce/dce_link_encoder.h"
15 #include "dce/dce_stream_encoder.h"
16
17 enum dc_status core_link_read_dpcd(
18 struct core_link* link,
19 uint32_t address,
20 uint8_t *data,
21 uint32_t size)
22 {
23 if (!dm_helpers_dp_read_dpcd(link->ctx,
24 &link->public,
25 address, data, size))
26 return DC_ERROR_UNEXPECTED;
27
28 return DC_OK;
29 }
30
31 enum dc_status core_link_write_dpcd(
32 struct core_link* link,
33 uint32_t address,
34 const uint8_t *data,
35 uint32_t size)
36 {
37 if (!dm_helpers_dp_write_dpcd(link->ctx,
38 &link->public,
39 address, data, size))
40 return DC_ERROR_UNEXPECTED;
41
42 return DC_OK;
43 }
44
45 void dp_receiver_power_ctrl(struct core_link *link, bool on)
46 {
47 uint8_t state;
48
49 state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
50
51 core_link_write_dpcd(link, DPCD_ADDRESS_POWER_STATE, &state,
52 sizeof(state));
53 }
54
55 void dp_enable_link_phy(
56 struct core_link *link,
57 enum signal_type signal,
58 enum clock_source_id clock_source,
59 const struct dc_link_settings *link_settings)
60 {
61 struct link_encoder *link_enc = link->link_enc;
62
63 if (dc_is_dp_sst_signal(signal)) {
64 if (signal == SIGNAL_TYPE_EDP) {
65 link_enc->funcs->power_control(link_enc, true);
66 link_enc->funcs->backlight_control(link_enc, true);
67 }
68
69 link_enc->funcs->enable_dp_output(
70 link_enc,
71 link_settings,
72 clock_source);
73 } else {
74 link_enc->funcs->enable_dp_mst_output(
75 link_enc,
76 link_settings,
77 clock_source);
78 }
79
80 dp_receiver_power_ctrl(link, true);
81 }
82
83 void dp_disable_link_phy(struct core_link *link, enum signal_type signal)
84 {
85 if (!link->wa_flags.dp_keep_receiver_powered)
86 dp_receiver_power_ctrl(link, false);
87
88 if (signal == SIGNAL_TYPE_EDP)
89 link->link_enc->funcs->backlight_control(link->link_enc, false);
90
91 link->link_enc->funcs->disable_output(link->link_enc, signal);
92
93 /* Clear current link setting.*/
94 memset(&link->public.cur_link_settings, 0,
95 sizeof(link->public.cur_link_settings));
96 }
97
98 void dp_disable_link_phy_mst(struct core_link *link, enum signal_type signal)
99 {
100 /* MST disable link only when no stream use the link */
101 if (link->mst_stream_alloc_table.stream_count > 0)
102 return;
103
104 dp_disable_link_phy(link, signal);
105 }
106
107 bool dp_set_hw_training_pattern(
108 struct core_link *link,
109 enum hw_dp_training_pattern pattern)
110 {
111 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
112
113 switch (pattern) {
114 case HW_DP_TRAINING_PATTERN_1:
115 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
116 break;
117 case HW_DP_TRAINING_PATTERN_2:
118 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
119 break;
120 case HW_DP_TRAINING_PATTERN_3:
121 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
122 break;
123 case HW_DP_TRAINING_PATTERN_4:
124 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
125 break;
126 default:
127 break;
128 }
129
130 dp_set_hw_test_pattern(link, test_pattern, NULL, 0);
131
132 return true;
133 }
134
135 void dp_set_hw_lane_settings(
136 struct core_link *link,
137 const struct link_training_settings *link_settings)
138 {
139 struct link_encoder *encoder = link->link_enc;
140
141 /* call Encoder to set lane settings */
142 encoder->funcs->dp_set_lane_settings(encoder, link_settings);
143 }
144
145 enum dp_panel_mode dp_get_panel_mode(struct core_link *link)
146 {
147 /* We need to explicitly check that connector
148 * is not DP. Some Travis_VGA get reported
149 * by video bios as DP.
150 */
151 if (link->public.connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
152
153 switch (link->dpcd_caps.branch_dev_id) {
154 case DP_BRANCH_DEVICE_ID_2:
155 if (strncmp(
156 link->dpcd_caps.branch_dev_name,
157 DP_VGA_LVDS_CONVERTER_ID_2,
158 sizeof(
159 link->dpcd_caps.
160 branch_dev_name)) == 0) {
161 return DP_PANEL_MODE_SPECIAL;
162 }
163 break;
164 case DP_BRANCH_DEVICE_ID_3:
165 if (strncmp(link->dpcd_caps.branch_dev_name,
166 DP_VGA_LVDS_CONVERTER_ID_3,
167 sizeof(
168 link->dpcd_caps.
169 branch_dev_name)) == 0) {
170 return DP_PANEL_MODE_SPECIAL;
171 }
172 break;
173 default:
174 break;
175 }
176
177 if (link->dpcd_caps.panel_mode_edp) {
178 return DP_PANEL_MODE_EDP;
179 }
180 }
181
182 return DP_PANEL_MODE_DEFAULT;
183 }
184
185 void dp_set_hw_test_pattern(
186 struct core_link *link,
187 enum dp_test_pattern test_pattern,
188 uint8_t *custom_pattern,
189 uint32_t custom_pattern_size)
190 {
191 struct encoder_set_dp_phy_pattern_param pattern_param = {0};
192 struct link_encoder *encoder = link->link_enc;
193
194 pattern_param.dp_phy_pattern = test_pattern;
195 pattern_param.custom_pattern = custom_pattern;
196 pattern_param.custom_pattern_size = custom_pattern_size;
197 pattern_param.dp_panel_mode = dp_get_panel_mode(link);
198
199 encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
200 }
201
202
203 void dp_retrain_link(struct core_link *link)
204 {
205 struct pipe_ctx *pipes = link->dc->current_context->res_ctx.pipe_ctx;
206 unsigned int i;
207
208 for (i = 0; i < MAX_PIPES; i++) {
209 if (pipes[i].stream_enc != NULL) {
210 dm_delay_in_microseconds(link->ctx, 100);
211 pipes->stream_enc->funcs->dp_blank(pipes[i].stream_enc);
212 link->dc->hwss.disable_stream(&pipes[i]);
213 dc_link_dp_perform_link_training(
214 &link->public,
215 &link->public.verified_link_cap,
216 true);
217 link->dc->hwss.enable_stream(&pipes[i]);
218 link->dc->hwss.unblank_stream(&pipes[i],
219 &link->public.verified_link_cap);
220 }
221 }
222 }