xref: /dflybsd-src/sys/dev/drm/radeon/radeon_dp_mst.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
1c59a5c48SFrançois Tigeot 
2c59a5c48SFrançois Tigeot #include <drm/drmP.h>
3c59a5c48SFrançois Tigeot #include <drm/drm_dp_mst_helper.h>
4c59a5c48SFrançois Tigeot #include <drm/drm_fb_helper.h>
5c59a5c48SFrançois Tigeot 
6c59a5c48SFrançois Tigeot #include "radeon.h"
7c59a5c48SFrançois Tigeot #include "atom.h"
8c59a5c48SFrançois Tigeot #include "ni_reg.h"
9c59a5c48SFrançois Tigeot 
10c59a5c48SFrançois Tigeot static struct radeon_encoder *radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector);
11c59a5c48SFrançois Tigeot 
radeon_atom_set_enc_offset(int id)12c59a5c48SFrançois Tigeot static int radeon_atom_set_enc_offset(int id)
13c59a5c48SFrançois Tigeot {
14c59a5c48SFrançois Tigeot 	static const int offsets[] = { EVERGREEN_CRTC0_REGISTER_OFFSET,
15c59a5c48SFrançois Tigeot 				       EVERGREEN_CRTC1_REGISTER_OFFSET,
16c59a5c48SFrançois Tigeot 				       EVERGREEN_CRTC2_REGISTER_OFFSET,
17c59a5c48SFrançois Tigeot 				       EVERGREEN_CRTC3_REGISTER_OFFSET,
18c59a5c48SFrançois Tigeot 				       EVERGREEN_CRTC4_REGISTER_OFFSET,
19c59a5c48SFrançois Tigeot 				       EVERGREEN_CRTC5_REGISTER_OFFSET,
20c59a5c48SFrançois Tigeot 				       0x13830 - 0x7030 };
21c59a5c48SFrançois Tigeot 
22c59a5c48SFrançois Tigeot 	return offsets[id];
23c59a5c48SFrançois Tigeot }
24c59a5c48SFrançois Tigeot 
radeon_dp_mst_set_be_cntl(struct radeon_encoder * primary,struct radeon_encoder_mst * mst_enc,enum radeon_hpd_id hpd,bool enable)25c59a5c48SFrançois Tigeot static int radeon_dp_mst_set_be_cntl(struct radeon_encoder *primary,
26c59a5c48SFrançois Tigeot 				     struct radeon_encoder_mst *mst_enc,
27c59a5c48SFrançois Tigeot 				     enum radeon_hpd_id hpd, bool enable)
28c59a5c48SFrançois Tigeot {
29c59a5c48SFrançois Tigeot 	struct drm_device *dev = primary->base.dev;
30c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
31c59a5c48SFrançois Tigeot 	uint32_t reg;
32c59a5c48SFrançois Tigeot 	int retries = 0;
33c59a5c48SFrançois Tigeot 	uint32_t temp;
34c59a5c48SFrançois Tigeot 
35c59a5c48SFrançois Tigeot 	reg = RREG32(NI_DIG_BE_CNTL + primary->offset);
36c59a5c48SFrançois Tigeot 
37c59a5c48SFrançois Tigeot 	/* set MST mode */
38c59a5c48SFrançois Tigeot 	reg &= ~NI_DIG_FE_DIG_MODE(7);
39c59a5c48SFrançois Tigeot 	reg |= NI_DIG_FE_DIG_MODE(NI_DIG_MODE_DP_MST);
40c59a5c48SFrançois Tigeot 
41c59a5c48SFrançois Tigeot 	if (enable)
42c59a5c48SFrançois Tigeot 		reg |= NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe);
43c59a5c48SFrançois Tigeot 	else
44c59a5c48SFrançois Tigeot 		reg &= ~NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe);
45c59a5c48SFrançois Tigeot 
46c59a5c48SFrançois Tigeot 	reg |= NI_DIG_HPD_SELECT(hpd);
47c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DIG_BE_CNTL + primary->offset, reg);
48c59a5c48SFrançois Tigeot 	WREG32(NI_DIG_BE_CNTL + primary->offset, reg);
49c59a5c48SFrançois Tigeot 
50c59a5c48SFrançois Tigeot 	if (enable) {
51c59a5c48SFrançois Tigeot 		uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe);
52c59a5c48SFrançois Tigeot 
53c59a5c48SFrançois Tigeot 		do {
54c59a5c48SFrançois Tigeot 			temp = RREG32(NI_DIG_FE_CNTL + offset);
55c59a5c48SFrançois Tigeot 		} while ((temp & NI_DIG_SYMCLK_FE_ON) && retries++ < 10000);
56c59a5c48SFrançois Tigeot 		if (retries == 10000)
57c59a5c48SFrançois Tigeot 			DRM_ERROR("timed out waiting for FE %d %d\n", primary->offset, mst_enc->fe);
58c59a5c48SFrançois Tigeot 	}
59c59a5c48SFrançois Tigeot 	return 0;
60c59a5c48SFrançois Tigeot }
61c59a5c48SFrançois Tigeot 
radeon_dp_mst_set_stream_attrib(struct radeon_encoder * primary,int stream_number,int fe,int slots)62c59a5c48SFrançois Tigeot static int radeon_dp_mst_set_stream_attrib(struct radeon_encoder *primary,
63c59a5c48SFrançois Tigeot 					   int stream_number,
64c59a5c48SFrançois Tigeot 					   int fe,
65c59a5c48SFrançois Tigeot 					   int slots)
66c59a5c48SFrançois Tigeot {
67c59a5c48SFrançois Tigeot 	struct drm_device *dev = primary->base.dev;
68c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
69c59a5c48SFrançois Tigeot 	u32 temp, val;
70c59a5c48SFrançois Tigeot 	int retries  = 0;
71c59a5c48SFrançois Tigeot 	int satreg, satidx;
72c59a5c48SFrançois Tigeot 
73c59a5c48SFrançois Tigeot 	satreg = stream_number >> 1;
74c59a5c48SFrançois Tigeot 	satidx = stream_number & 1;
75c59a5c48SFrançois Tigeot 
76c59a5c48SFrançois Tigeot 	temp = RREG32(NI_DP_MSE_SAT0 + satreg + primary->offset);
77c59a5c48SFrançois Tigeot 
78c59a5c48SFrançois Tigeot 	val = NI_DP_MSE_SAT_SLOT_COUNT0(slots) | NI_DP_MSE_SAT_SRC0(fe);
79c59a5c48SFrançois Tigeot 
80c59a5c48SFrançois Tigeot 	val <<= (16 * satidx);
81c59a5c48SFrançois Tigeot 
82c59a5c48SFrançois Tigeot 	temp &= ~(0xffff << (16 * satidx));
83c59a5c48SFrançois Tigeot 
84c59a5c48SFrançois Tigeot 	temp |= val;
85c59a5c48SFrançois Tigeot 
86c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DP_MSE_SAT0 + satreg + primary->offset, temp);
87c59a5c48SFrançois Tigeot 	WREG32(NI_DP_MSE_SAT0 + satreg + primary->offset, temp);
88c59a5c48SFrançois Tigeot 
89c59a5c48SFrançois Tigeot 	WREG32(NI_DP_MSE_SAT_UPDATE + primary->offset, 1);
90c59a5c48SFrançois Tigeot 
91c59a5c48SFrançois Tigeot 	do {
92d78d3a22SFrançois Tigeot 		unsigned value1, value2;
93d78d3a22SFrançois Tigeot 		udelay(10);
94c59a5c48SFrançois Tigeot 		temp = RREG32(NI_DP_MSE_SAT_UPDATE + primary->offset);
95d78d3a22SFrançois Tigeot 
96d78d3a22SFrançois Tigeot 		value1 = temp & NI_DP_MSE_SAT_UPDATE_MASK;
97d78d3a22SFrançois Tigeot 		value2 = temp & NI_DP_MSE_16_MTP_KEEPOUT;
98d78d3a22SFrançois Tigeot 
99d78d3a22SFrançois Tigeot 		if (!value1 && !value2)
100d78d3a22SFrançois Tigeot 			break;
101d78d3a22SFrançois Tigeot 	} while (retries++ < 50);
102c59a5c48SFrançois Tigeot 
103c59a5c48SFrançois Tigeot 	if (retries == 10000)
104c59a5c48SFrançois Tigeot 		DRM_ERROR("timed out waitin for SAT update %d\n", primary->offset);
105c59a5c48SFrançois Tigeot 
106c59a5c48SFrançois Tigeot 	/* MTP 16 ? */
107c59a5c48SFrançois Tigeot 	return 0;
108c59a5c48SFrançois Tigeot }
109c59a5c48SFrançois Tigeot 
radeon_dp_mst_update_stream_attribs(struct radeon_connector * mst_conn,struct radeon_encoder * primary)110c59a5c48SFrançois Tigeot static int radeon_dp_mst_update_stream_attribs(struct radeon_connector *mst_conn,
111c59a5c48SFrançois Tigeot 					       struct radeon_encoder *primary)
112c59a5c48SFrançois Tigeot {
113c59a5c48SFrançois Tigeot 	struct drm_device *dev = mst_conn->base.dev;
114c59a5c48SFrançois Tigeot 	struct stream_attribs new_attribs[6];
115c59a5c48SFrançois Tigeot 	int i;
116c59a5c48SFrançois Tigeot 	int idx = 0;
117c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector;
118c59a5c48SFrançois Tigeot 	struct drm_connector *connector;
119c59a5c48SFrançois Tigeot 
120c59a5c48SFrançois Tigeot 	memset(new_attribs, 0, sizeof(new_attribs));
121c59a5c48SFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
122c59a5c48SFrançois Tigeot 		struct radeon_encoder *subenc;
123c59a5c48SFrançois Tigeot 		struct radeon_encoder_mst *mst_enc;
124c59a5c48SFrançois Tigeot 
125c59a5c48SFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
126c59a5c48SFrançois Tigeot 		if (!radeon_connector->is_mst_connector)
127c59a5c48SFrançois Tigeot 			continue;
128c59a5c48SFrançois Tigeot 
129c59a5c48SFrançois Tigeot 		if (radeon_connector->mst_port != mst_conn)
130c59a5c48SFrançois Tigeot 			continue;
131c59a5c48SFrançois Tigeot 
132c59a5c48SFrançois Tigeot 		subenc = radeon_connector->mst_encoder;
133c59a5c48SFrançois Tigeot 		mst_enc = subenc->enc_priv;
134c59a5c48SFrançois Tigeot 
135c59a5c48SFrançois Tigeot 		if (!mst_enc->enc_active)
136c59a5c48SFrançois Tigeot 			continue;
137c59a5c48SFrançois Tigeot 
138c59a5c48SFrançois Tigeot 		new_attribs[idx].fe = mst_enc->fe;
139c59a5c48SFrançois Tigeot 		new_attribs[idx].slots = drm_dp_mst_get_vcpi_slots(&mst_conn->mst_mgr, mst_enc->port);
140c59a5c48SFrançois Tigeot 		idx++;
141c59a5c48SFrançois Tigeot 	}
142c59a5c48SFrançois Tigeot 
143c59a5c48SFrançois Tigeot 	for (i = 0; i < idx; i++) {
144c59a5c48SFrançois Tigeot 		if (new_attribs[i].fe != mst_conn->cur_stream_attribs[i].fe ||
145c59a5c48SFrançois Tigeot 		    new_attribs[i].slots != mst_conn->cur_stream_attribs[i].slots) {
146c59a5c48SFrançois Tigeot 			radeon_dp_mst_set_stream_attrib(primary, i, new_attribs[i].fe, new_attribs[i].slots);
147c59a5c48SFrançois Tigeot 			mst_conn->cur_stream_attribs[i].fe = new_attribs[i].fe;
148c59a5c48SFrançois Tigeot 			mst_conn->cur_stream_attribs[i].slots = new_attribs[i].slots;
149c59a5c48SFrançois Tigeot 		}
150c59a5c48SFrançois Tigeot 	}
151c59a5c48SFrançois Tigeot 
152c59a5c48SFrançois Tigeot 	for (i = idx; i < mst_conn->enabled_attribs; i++) {
153c59a5c48SFrançois Tigeot 		radeon_dp_mst_set_stream_attrib(primary, i, 0, 0);
154c59a5c48SFrançois Tigeot 		mst_conn->cur_stream_attribs[i].fe = 0;
155c59a5c48SFrançois Tigeot 		mst_conn->cur_stream_attribs[i].slots = 0;
156c59a5c48SFrançois Tigeot 	}
157c59a5c48SFrançois Tigeot 	mst_conn->enabled_attribs = idx;
158c59a5c48SFrançois Tigeot 	return 0;
159c59a5c48SFrançois Tigeot }
160c59a5c48SFrançois Tigeot 
radeon_dp_mst_set_vcp_size(struct radeon_encoder * mst,s64 avg_time_slots_per_mtp)161d78d3a22SFrançois Tigeot static int radeon_dp_mst_set_vcp_size(struct radeon_encoder *mst, s64 avg_time_slots_per_mtp)
162c59a5c48SFrançois Tigeot {
163c59a5c48SFrançois Tigeot 	struct drm_device *dev = mst->base.dev;
164c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
165c59a5c48SFrançois Tigeot 	struct radeon_encoder_mst *mst_enc = mst->enc_priv;
166c59a5c48SFrançois Tigeot 	uint32_t val, temp;
167c59a5c48SFrançois Tigeot 	uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe);
168c59a5c48SFrançois Tigeot 	int retries = 0;
169d78d3a22SFrançois Tigeot 	uint32_t x = drm_fixp2int(avg_time_slots_per_mtp);
170d78d3a22SFrançois Tigeot 	uint32_t y = drm_fixp2int_ceil((avg_time_slots_per_mtp - x) << 26);
171c59a5c48SFrançois Tigeot 
172c59a5c48SFrançois Tigeot 	val = NI_DP_MSE_RATE_X(x) | NI_DP_MSE_RATE_Y(y);
173c59a5c48SFrançois Tigeot 
174c59a5c48SFrançois Tigeot 	WREG32(NI_DP_MSE_RATE_CNTL + offset, val);
175c59a5c48SFrançois Tigeot 
176c59a5c48SFrançois Tigeot 	do {
177c59a5c48SFrançois Tigeot 		temp = RREG32(NI_DP_MSE_RATE_UPDATE + offset);
178d78d3a22SFrançois Tigeot 		udelay(10);
179c59a5c48SFrançois Tigeot 	} while ((temp & 0x1) && (retries++ < 10000));
180c59a5c48SFrançois Tigeot 
181c59a5c48SFrançois Tigeot 	if (retries >= 10000)
182c59a5c48SFrançois Tigeot 		DRM_ERROR("timed out wait for rate cntl %d\n", mst_enc->fe);
183c59a5c48SFrançois Tigeot 	return 0;
184c59a5c48SFrançois Tigeot }
185c59a5c48SFrançois Tigeot 
radeon_dp_mst_get_ddc_modes(struct drm_connector * connector)186c59a5c48SFrançois Tigeot static int radeon_dp_mst_get_ddc_modes(struct drm_connector *connector)
187c59a5c48SFrançois Tigeot {
188c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
189c59a5c48SFrançois Tigeot 	struct radeon_connector *master = radeon_connector->mst_port;
190c59a5c48SFrançois Tigeot 	struct edid *edid;
191c59a5c48SFrançois Tigeot 	int ret = 0;
192c59a5c48SFrançois Tigeot 
193c59a5c48SFrançois Tigeot 	edid = drm_dp_mst_get_edid(connector, &master->mst_mgr, radeon_connector->port);
194c59a5c48SFrançois Tigeot 	radeon_connector->edid = edid;
195c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("edid retrieved %p\n", edid);
196c59a5c48SFrançois Tigeot 	if (radeon_connector->edid) {
197c59a5c48SFrançois Tigeot 		drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
198c59a5c48SFrançois Tigeot 		ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
199c59a5c48SFrançois Tigeot 		drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid);
200c59a5c48SFrançois Tigeot 		return ret;
201c59a5c48SFrançois Tigeot 	}
202c59a5c48SFrançois Tigeot 	drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
203c59a5c48SFrançois Tigeot 
204c59a5c48SFrançois Tigeot 	return ret;
205c59a5c48SFrançois Tigeot }
206c59a5c48SFrançois Tigeot 
radeon_dp_mst_get_modes(struct drm_connector * connector)207c59a5c48SFrançois Tigeot static int radeon_dp_mst_get_modes(struct drm_connector *connector)
208c59a5c48SFrançois Tigeot {
209c59a5c48SFrançois Tigeot 	return radeon_dp_mst_get_ddc_modes(connector);
210c59a5c48SFrançois Tigeot }
211c59a5c48SFrançois Tigeot 
212c59a5c48SFrançois Tigeot static enum drm_mode_status
radeon_dp_mst_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)213c59a5c48SFrançois Tigeot radeon_dp_mst_mode_valid(struct drm_connector *connector,
214c59a5c48SFrançois Tigeot 			struct drm_display_mode *mode)
215c59a5c48SFrançois Tigeot {
216c59a5c48SFrançois Tigeot 	/* TODO - validate mode against available PBN for link */
217c59a5c48SFrançois Tigeot 	if (mode->clock < 10000)
218c59a5c48SFrançois Tigeot 		return MODE_CLOCK_LOW;
219c59a5c48SFrançois Tigeot 
220c59a5c48SFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
221c59a5c48SFrançois Tigeot 		return MODE_H_ILLEGAL;
222c59a5c48SFrançois Tigeot 
223c59a5c48SFrançois Tigeot 	return MODE_OK;
224c59a5c48SFrançois Tigeot }
225c59a5c48SFrançois Tigeot 
radeon_mst_best_encoder(struct drm_connector * connector)226c59a5c48SFrançois Tigeot static struct drm_encoder *radeon_mst_best_encoder(struct drm_connector *connector)
227c59a5c48SFrançois Tigeot {
228c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
229c59a5c48SFrançois Tigeot 
230c59a5c48SFrançois Tigeot 	return &radeon_connector->mst_encoder->base;
231c59a5c48SFrançois Tigeot }
232c59a5c48SFrançois Tigeot 
233c59a5c48SFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dp_mst_connector_helper_funcs = {
234c59a5c48SFrançois Tigeot 	.get_modes = radeon_dp_mst_get_modes,
235c59a5c48SFrançois Tigeot 	.mode_valid = radeon_dp_mst_mode_valid,
236c59a5c48SFrançois Tigeot 	.best_encoder = radeon_mst_best_encoder,
237c59a5c48SFrançois Tigeot };
238c59a5c48SFrançois Tigeot 
239c59a5c48SFrançois Tigeot static enum drm_connector_status
radeon_dp_mst_detect(struct drm_connector * connector,bool force)240c59a5c48SFrançois Tigeot radeon_dp_mst_detect(struct drm_connector *connector, bool force)
241c59a5c48SFrançois Tigeot {
242c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
243c59a5c48SFrançois Tigeot 	struct radeon_connector *master = radeon_connector->mst_port;
244c59a5c48SFrançois Tigeot 
245c59a5c48SFrançois Tigeot 	return drm_dp_mst_detect_port(connector, &master->mst_mgr, radeon_connector->port);
246c59a5c48SFrançois Tigeot }
247c59a5c48SFrançois Tigeot 
248c59a5c48SFrançois Tigeot static void
radeon_dp_mst_connector_destroy(struct drm_connector * connector)249c59a5c48SFrançois Tigeot radeon_dp_mst_connector_destroy(struct drm_connector *connector)
250c59a5c48SFrançois Tigeot {
251c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
252c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = radeon_connector->mst_encoder;
253c59a5c48SFrançois Tigeot 
254c59a5c48SFrançois Tigeot 	drm_encoder_cleanup(&radeon_encoder->base);
255c59a5c48SFrançois Tigeot 	kfree(radeon_encoder);
256c59a5c48SFrançois Tigeot 	drm_connector_cleanup(connector);
257c59a5c48SFrançois Tigeot 	kfree(radeon_connector);
258c59a5c48SFrançois Tigeot }
259c59a5c48SFrançois Tigeot 
260c59a5c48SFrançois Tigeot static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = {
261d78d3a22SFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
262c59a5c48SFrançois Tigeot 	.detect = radeon_dp_mst_detect,
263c59a5c48SFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
264c59a5c48SFrançois Tigeot 	.destroy = radeon_dp_mst_connector_destroy,
265c59a5c48SFrançois Tigeot };
266c59a5c48SFrançois Tigeot 
radeon_dp_add_mst_connector(struct drm_dp_mst_topology_mgr * mgr,struct drm_dp_mst_port * port,const char * pathprop)267c59a5c48SFrançois Tigeot static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
268c59a5c48SFrançois Tigeot 							 struct drm_dp_mst_port *port,
269c59a5c48SFrançois Tigeot 							 const char *pathprop)
270c59a5c48SFrançois Tigeot {
271c59a5c48SFrançois Tigeot 	struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
272c59a5c48SFrançois Tigeot 	struct drm_device *dev = master->base.dev;
273c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector;
274c59a5c48SFrançois Tigeot 	struct drm_connector *connector;
275c59a5c48SFrançois Tigeot 
276c59a5c48SFrançois Tigeot 	radeon_connector = kzalloc(sizeof(*radeon_connector), GFP_KERNEL);
277c59a5c48SFrançois Tigeot 	if (!radeon_connector)
278c59a5c48SFrançois Tigeot 		return NULL;
279c59a5c48SFrançois Tigeot 
280c59a5c48SFrançois Tigeot 	radeon_connector->is_mst_connector = true;
281c59a5c48SFrançois Tigeot 	connector = &radeon_connector->base;
282c59a5c48SFrançois Tigeot 	radeon_connector->port = port;
283c59a5c48SFrançois Tigeot 	radeon_connector->mst_port = master;
284c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("\n");
285c59a5c48SFrançois Tigeot 
286c59a5c48SFrançois Tigeot 	drm_connector_init(dev, connector, &radeon_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort);
287c59a5c48SFrançois Tigeot 	drm_connector_helper_add(connector, &radeon_dp_mst_connector_helper_funcs);
288c59a5c48SFrançois Tigeot 	radeon_connector->mst_encoder = radeon_dp_create_fake_mst_encoder(master);
289c59a5c48SFrançois Tigeot 
290c59a5c48SFrançois Tigeot 	drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
291c59a5c48SFrançois Tigeot 	drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0);
292c59a5c48SFrançois Tigeot 	drm_mode_connector_set_path_property(connector, pathprop);
293c59a5c48SFrançois Tigeot 
294c59a5c48SFrançois Tigeot 	return connector;
295c59a5c48SFrançois Tigeot }
296c59a5c48SFrançois Tigeot 
radeon_dp_register_mst_connector(struct drm_connector * connector)297c59a5c48SFrançois Tigeot static void radeon_dp_register_mst_connector(struct drm_connector *connector)
298c59a5c48SFrançois Tigeot {
299c59a5c48SFrançois Tigeot 	struct drm_device *dev = connector->dev;
300c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
301c59a5c48SFrançois Tigeot 
302c59a5c48SFrançois Tigeot 	radeon_fb_add_connector(rdev, connector);
303c59a5c48SFrançois Tigeot 
304c59a5c48SFrançois Tigeot 	drm_connector_register(connector);
305c59a5c48SFrançois Tigeot }
306c59a5c48SFrançois Tigeot 
radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr * mgr,struct drm_connector * connector)307c59a5c48SFrançois Tigeot static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
308c59a5c48SFrançois Tigeot 					    struct drm_connector *connector)
309c59a5c48SFrançois Tigeot {
310c59a5c48SFrançois Tigeot 	struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
311c59a5c48SFrançois Tigeot 	struct drm_device *dev = master->base.dev;
312c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
313c59a5c48SFrançois Tigeot 
314c59a5c48SFrançois Tigeot 	drm_connector_unregister(connector);
315c59a5c48SFrançois Tigeot 	radeon_fb_remove_connector(rdev, connector);
316c59a5c48SFrançois Tigeot 	drm_connector_cleanup(connector);
317c59a5c48SFrançois Tigeot 
318c59a5c48SFrançois Tigeot 	kfree(connector);
319c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("\n");
320c59a5c48SFrançois Tigeot }
321c59a5c48SFrançois Tigeot 
radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr * mgr)322c59a5c48SFrançois Tigeot static void radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
323c59a5c48SFrançois Tigeot {
324c59a5c48SFrançois Tigeot 	struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
325c59a5c48SFrançois Tigeot 	struct drm_device *dev = master->base.dev;
326c59a5c48SFrançois Tigeot 
327c59a5c48SFrançois Tigeot 	drm_kms_helper_hotplug_event(dev);
328c59a5c48SFrançois Tigeot }
329c59a5c48SFrançois Tigeot 
330d78d3a22SFrançois Tigeot const struct drm_dp_mst_topology_cbs mst_cbs = {
331c59a5c48SFrançois Tigeot 	.add_connector = radeon_dp_add_mst_connector,
332c59a5c48SFrançois Tigeot 	.register_connector = radeon_dp_register_mst_connector,
333c59a5c48SFrançois Tigeot 	.destroy_connector = radeon_dp_destroy_mst_connector,
334c59a5c48SFrançois Tigeot 	.hotplug = radeon_dp_mst_hotplug,
335c59a5c48SFrançois Tigeot };
336c59a5c48SFrançois Tigeot 
radeon_mst_find_connector(struct drm_encoder * encoder)337c59a5c48SFrançois Tigeot static struct radeon_connector *radeon_mst_find_connector(struct drm_encoder *encoder)
338c59a5c48SFrançois Tigeot {
339c59a5c48SFrançois Tigeot 	struct drm_device *dev = encoder->dev;
340c59a5c48SFrançois Tigeot 	struct drm_connector *connector;
341c59a5c48SFrançois Tigeot 
342c59a5c48SFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
343c59a5c48SFrançois Tigeot 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
344c59a5c48SFrançois Tigeot 		if (!connector->encoder)
345c59a5c48SFrançois Tigeot 			continue;
346c59a5c48SFrançois Tigeot 		if (!radeon_connector->is_mst_connector)
347c59a5c48SFrançois Tigeot 			continue;
348c59a5c48SFrançois Tigeot 
349c59a5c48SFrançois Tigeot 		DRM_DEBUG_KMS("checking %p vs %p\n", connector->encoder, encoder);
350c59a5c48SFrançois Tigeot 		if (connector->encoder == encoder)
351c59a5c48SFrançois Tigeot 			return radeon_connector;
352c59a5c48SFrançois Tigeot 	}
353c59a5c48SFrançois Tigeot 	return NULL;
354c59a5c48SFrançois Tigeot }
355c59a5c48SFrançois Tigeot 
radeon_dp_mst_prepare_pll(struct drm_crtc * crtc,struct drm_display_mode * mode)356c59a5c48SFrançois Tigeot void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
357c59a5c48SFrançois Tigeot {
358c59a5c48SFrançois Tigeot 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
359c59a5c48SFrançois Tigeot 	struct drm_device *dev = crtc->dev;
360c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
361c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(radeon_crtc->encoder);
362c59a5c48SFrançois Tigeot 	struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv;
363c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector = radeon_mst_find_connector(&radeon_encoder->base);
364c59a5c48SFrançois Tigeot 	int dp_clock;
365c59a5c48SFrançois Tigeot 	struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv;
366c59a5c48SFrançois Tigeot 
367c59a5c48SFrançois Tigeot 	if (radeon_connector) {
368c59a5c48SFrançois Tigeot 		radeon_connector->pixelclock_for_modeset = mode->clock;
369c59a5c48SFrançois Tigeot 		if (radeon_connector->base.display_info.bpc)
370c59a5c48SFrançois Tigeot 			radeon_crtc->bpc = radeon_connector->base.display_info.bpc;
371c59a5c48SFrançois Tigeot 		else
372c59a5c48SFrançois Tigeot 			radeon_crtc->bpc = 8;
373c59a5c48SFrançois Tigeot 	}
374c59a5c48SFrançois Tigeot 
375c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("dp_clock %p %d\n", dig_connector, dig_connector->dp_clock);
376c59a5c48SFrançois Tigeot 	dp_clock = dig_connector->dp_clock;
377c59a5c48SFrançois Tigeot 	radeon_crtc->ss_enabled =
378c59a5c48SFrançois Tigeot 		radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss,
379c59a5c48SFrançois Tigeot 						 ASIC_INTERNAL_SS_ON_DP,
380c59a5c48SFrançois Tigeot 						 dp_clock);
381c59a5c48SFrançois Tigeot }
382c59a5c48SFrançois Tigeot 
383c59a5c48SFrançois Tigeot static void
radeon_mst_encoder_dpms(struct drm_encoder * encoder,int mode)384c59a5c48SFrançois Tigeot radeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode)
385c59a5c48SFrançois Tigeot {
386c59a5c48SFrançois Tigeot 	struct drm_device *dev = encoder->dev;
387c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
388c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder, *primary;
389c59a5c48SFrançois Tigeot 	struct radeon_encoder_mst *mst_enc;
390c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig_enc;
391c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector;
392c59a5c48SFrançois Tigeot 	struct drm_crtc *crtc;
393c59a5c48SFrançois Tigeot 	struct radeon_crtc *radeon_crtc;
394c59a5c48SFrançois Tigeot 	int ret, slots;
395d78d3a22SFrançois Tigeot 	s64 fixed_pbn, fixed_pbn_per_slot, avg_time_slots_per_mtp;
396c59a5c48SFrançois Tigeot 	if (!ASIC_IS_DCE5(rdev)) {
397c59a5c48SFrançois Tigeot 		DRM_ERROR("got mst dpms on non-DCE5\n");
398c59a5c48SFrançois Tigeot 		return;
399c59a5c48SFrançois Tigeot 	}
400c59a5c48SFrançois Tigeot 
401c59a5c48SFrançois Tigeot 	radeon_connector = radeon_mst_find_connector(encoder);
402c59a5c48SFrançois Tigeot 	if (!radeon_connector)
403c59a5c48SFrançois Tigeot 		return;
404c59a5c48SFrançois Tigeot 
405c59a5c48SFrançois Tigeot 	radeon_encoder = to_radeon_encoder(encoder);
406c59a5c48SFrançois Tigeot 
407c59a5c48SFrançois Tigeot 	mst_enc = radeon_encoder->enc_priv;
408c59a5c48SFrançois Tigeot 
409c59a5c48SFrançois Tigeot 	primary = mst_enc->primary;
410c59a5c48SFrançois Tigeot 
411c59a5c48SFrançois Tigeot 	dig_enc = primary->enc_priv;
412c59a5c48SFrançois Tigeot 
413c59a5c48SFrançois Tigeot 	crtc = encoder->crtc;
414c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("got connector %d\n", dig_enc->active_mst_links);
415c59a5c48SFrançois Tigeot 
416c59a5c48SFrançois Tigeot 	switch (mode) {
417c59a5c48SFrançois Tigeot 	case DRM_MODE_DPMS_ON:
418c59a5c48SFrançois Tigeot 		dig_enc->active_mst_links++;
419c59a5c48SFrançois Tigeot 
420c59a5c48SFrançois Tigeot 		radeon_crtc = to_radeon_crtc(crtc);
421c59a5c48SFrançois Tigeot 
422c59a5c48SFrançois Tigeot 		if (dig_enc->active_mst_links == 1) {
423c59a5c48SFrançois Tigeot 			mst_enc->fe = dig_enc->dig_encoder;
424c59a5c48SFrançois Tigeot 			mst_enc->fe_from_be = true;
425c59a5c48SFrançois Tigeot 			atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe);
426c59a5c48SFrançois Tigeot 
427c59a5c48SFrançois Tigeot 			atombios_dig_encoder_setup(&primary->base, ATOM_ENCODER_CMD_SETUP, 0);
428c59a5c48SFrançois Tigeot 			atombios_dig_transmitter_setup2(&primary->base, ATOM_TRANSMITTER_ACTION_ENABLE,
429c59a5c48SFrançois Tigeot 							0, 0, dig_enc->dig_encoder);
430c59a5c48SFrançois Tigeot 
431c59a5c48SFrançois Tigeot 			if (radeon_dp_needs_link_train(mst_enc->connector) ||
432c59a5c48SFrançois Tigeot 			    dig_enc->active_mst_links == 1) {
433c59a5c48SFrançois Tigeot 				radeon_dp_link_train(&primary->base, &mst_enc->connector->base);
434c59a5c48SFrançois Tigeot 			}
435c59a5c48SFrançois Tigeot 
436c59a5c48SFrançois Tigeot 		} else {
437c59a5c48SFrançois Tigeot 			mst_enc->fe = radeon_atom_pick_dig_encoder(encoder, radeon_crtc->crtc_id);
438c59a5c48SFrançois Tigeot 			if (mst_enc->fe == -1)
439c59a5c48SFrançois Tigeot 				DRM_ERROR("failed to get frontend for dig encoder\n");
440c59a5c48SFrançois Tigeot 			mst_enc->fe_from_be = false;
441c59a5c48SFrançois Tigeot 			atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe);
442c59a5c48SFrançois Tigeot 		}
443c59a5c48SFrançois Tigeot 
444c59a5c48SFrançois Tigeot 		DRM_DEBUG_KMS("dig encoder is %d %d %d\n", dig_enc->dig_encoder,
445c59a5c48SFrançois Tigeot 			      dig_enc->linkb, radeon_crtc->crtc_id);
446c59a5c48SFrançois Tigeot 
447*a85cb24fSFrançois Tigeot 		slots = drm_dp_find_vcpi_slots(&radeon_connector->mst_port->mst_mgr,
448*a85cb24fSFrançois Tigeot 					       mst_enc->pbn);
449c59a5c48SFrançois Tigeot 		ret = drm_dp_mst_allocate_vcpi(&radeon_connector->mst_port->mst_mgr,
450c59a5c48SFrançois Tigeot 					       radeon_connector->port,
451*a85cb24fSFrançois Tigeot 					       mst_enc->pbn, slots);
452c59a5c48SFrançois Tigeot 		ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr);
453c59a5c48SFrançois Tigeot 
454c59a5c48SFrançois Tigeot 		radeon_dp_mst_set_be_cntl(primary, mst_enc,
455c59a5c48SFrançois Tigeot 					  radeon_connector->mst_port->hpd.hpd, true);
456c59a5c48SFrançois Tigeot 
457c59a5c48SFrançois Tigeot 		mst_enc->enc_active = true;
458c59a5c48SFrançois Tigeot 		radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary);
459d78d3a22SFrançois Tigeot 
460d78d3a22SFrançois Tigeot 		fixed_pbn = drm_int2fixp(mst_enc->pbn);
461d78d3a22SFrançois Tigeot 		fixed_pbn_per_slot = drm_int2fixp(radeon_connector->mst_port->mst_mgr.pbn_div);
462d78d3a22SFrançois Tigeot 		avg_time_slots_per_mtp = drm_fixp_div(fixed_pbn, fixed_pbn_per_slot);
463d78d3a22SFrançois Tigeot 		radeon_dp_mst_set_vcp_size(radeon_encoder, avg_time_slots_per_mtp);
464c59a5c48SFrançois Tigeot 
465c59a5c48SFrançois Tigeot 		atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0,
466c59a5c48SFrançois Tigeot 					    mst_enc->fe);
467c59a5c48SFrançois Tigeot 		ret = drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr);
468c59a5c48SFrançois Tigeot 
469c59a5c48SFrançois Tigeot 		ret = drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr);
470c59a5c48SFrançois Tigeot 
471c59a5c48SFrançois Tigeot 		break;
472c59a5c48SFrançois Tigeot 	case DRM_MODE_DPMS_STANDBY:
473c59a5c48SFrançois Tigeot 	case DRM_MODE_DPMS_SUSPEND:
474c59a5c48SFrançois Tigeot 	case DRM_MODE_DPMS_OFF:
475c59a5c48SFrançois Tigeot 		DRM_ERROR("DPMS OFF %d\n", dig_enc->active_mst_links);
476c59a5c48SFrançois Tigeot 
477c59a5c48SFrançois Tigeot 		if (!mst_enc->enc_active)
478c59a5c48SFrançois Tigeot 			return;
479c59a5c48SFrançois Tigeot 
480c59a5c48SFrançois Tigeot 		drm_dp_mst_reset_vcpi_slots(&radeon_connector->mst_port->mst_mgr, mst_enc->port);
481c59a5c48SFrançois Tigeot 		ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr);
482c59a5c48SFrançois Tigeot 
483c59a5c48SFrançois Tigeot 		drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr);
484c59a5c48SFrançois Tigeot 		/* and this can also fail */
485c59a5c48SFrançois Tigeot 		drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr);
486c59a5c48SFrançois Tigeot 
487c59a5c48SFrançois Tigeot 		drm_dp_mst_deallocate_vcpi(&radeon_connector->mst_port->mst_mgr, mst_enc->port);
488c59a5c48SFrançois Tigeot 
489c59a5c48SFrançois Tigeot 		mst_enc->enc_active = false;
490c59a5c48SFrançois Tigeot 		radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary);
491c59a5c48SFrançois Tigeot 
492c59a5c48SFrançois Tigeot 		radeon_dp_mst_set_be_cntl(primary, mst_enc,
493c59a5c48SFrançois Tigeot 					  radeon_connector->mst_port->hpd.hpd, false);
494c59a5c48SFrançois Tigeot 		atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0,
495c59a5c48SFrançois Tigeot 					    mst_enc->fe);
496c59a5c48SFrançois Tigeot 
497c59a5c48SFrançois Tigeot 		if (!mst_enc->fe_from_be)
498c59a5c48SFrançois Tigeot 			radeon_atom_release_dig_encoder(rdev, mst_enc->fe);
499c59a5c48SFrançois Tigeot 
500c59a5c48SFrançois Tigeot 		mst_enc->fe_from_be = false;
501c59a5c48SFrançois Tigeot 		dig_enc->active_mst_links--;
502c59a5c48SFrançois Tigeot 		if (dig_enc->active_mst_links == 0) {
503c59a5c48SFrançois Tigeot 			/* drop link */
504c59a5c48SFrançois Tigeot 		}
505c59a5c48SFrançois Tigeot 
506c59a5c48SFrançois Tigeot 		break;
507c59a5c48SFrançois Tigeot 	}
508c59a5c48SFrançois Tigeot 
509c59a5c48SFrançois Tigeot }
510c59a5c48SFrançois Tigeot 
radeon_mst_mode_fixup(struct drm_encoder * encoder,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)511c59a5c48SFrançois Tigeot static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
512c59a5c48SFrançois Tigeot 				   const struct drm_display_mode *mode,
513c59a5c48SFrançois Tigeot 				   struct drm_display_mode *adjusted_mode)
514c59a5c48SFrançois Tigeot {
515c59a5c48SFrançois Tigeot 	struct radeon_encoder_mst *mst_enc;
516c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
517d78d3a22SFrançois Tigeot 	struct radeon_connector_atom_dig *dig_connector;
518c59a5c48SFrançois Tigeot 	int bpp = 24;
519c59a5c48SFrançois Tigeot 
520c59a5c48SFrançois Tigeot 	mst_enc = radeon_encoder->enc_priv;
521c59a5c48SFrançois Tigeot 
522c59a5c48SFrançois Tigeot 	mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp);
523c59a5c48SFrançois Tigeot 
524c59a5c48SFrançois Tigeot 	mst_enc->primary->active_device = mst_enc->primary->devices & mst_enc->connector->devices;
525c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n",
526c59a5c48SFrançois Tigeot 		      mst_enc->primary->active_device, mst_enc->primary->devices,
527c59a5c48SFrançois Tigeot 		      mst_enc->connector->devices, mst_enc->primary->base.encoder_type);
528c59a5c48SFrançois Tigeot 
529c59a5c48SFrançois Tigeot 
530c59a5c48SFrançois Tigeot 	drm_mode_set_crtcinfo(adjusted_mode, 0);
531c59a5c48SFrançois Tigeot 	dig_connector = mst_enc->connector->con_priv;
532c59a5c48SFrançois Tigeot 	dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
533c59a5c48SFrançois Tigeot 	dig_connector->dp_clock = drm_dp_max_link_rate(dig_connector->dpcd);
534c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
535c59a5c48SFrançois Tigeot 		      dig_connector->dp_lane_count, dig_connector->dp_clock);
536c59a5c48SFrançois Tigeot 	return true;
537c59a5c48SFrançois Tigeot }
538c59a5c48SFrançois Tigeot 
radeon_mst_encoder_prepare(struct drm_encoder * encoder)539c59a5c48SFrançois Tigeot static void radeon_mst_encoder_prepare(struct drm_encoder *encoder)
540c59a5c48SFrançois Tigeot {
541c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector;
542c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder, *primary;
543c59a5c48SFrançois Tigeot 	struct radeon_encoder_mst *mst_enc;
544c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig_enc;
545c59a5c48SFrançois Tigeot 
546c59a5c48SFrançois Tigeot 	radeon_connector = radeon_mst_find_connector(encoder);
547c59a5c48SFrançois Tigeot 	if (!radeon_connector) {
548c59a5c48SFrançois Tigeot 		DRM_DEBUG_KMS("failed to find connector %p\n", encoder);
549c59a5c48SFrançois Tigeot 		return;
550c59a5c48SFrançois Tigeot 	}
551c59a5c48SFrançois Tigeot 	radeon_encoder = to_radeon_encoder(encoder);
552c59a5c48SFrançois Tigeot 
553c59a5c48SFrançois Tigeot 	radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
554c59a5c48SFrançois Tigeot 
555c59a5c48SFrançois Tigeot 	mst_enc = radeon_encoder->enc_priv;
556c59a5c48SFrançois Tigeot 
557c59a5c48SFrançois Tigeot 	primary = mst_enc->primary;
558c59a5c48SFrançois Tigeot 
559c59a5c48SFrançois Tigeot 	dig_enc = primary->enc_priv;
560c59a5c48SFrançois Tigeot 
561c59a5c48SFrançois Tigeot 	mst_enc->port = radeon_connector->port;
562c59a5c48SFrançois Tigeot 
563c59a5c48SFrançois Tigeot 	if (dig_enc->dig_encoder == -1) {
564c59a5c48SFrançois Tigeot 		dig_enc->dig_encoder = radeon_atom_pick_dig_encoder(&primary->base, -1);
565c59a5c48SFrançois Tigeot 		primary->offset = radeon_atom_set_enc_offset(dig_enc->dig_encoder);
566c59a5c48SFrançois Tigeot 		atombios_set_mst_encoder_crtc_source(encoder, dig_enc->dig_encoder);
567c59a5c48SFrançois Tigeot 
568c59a5c48SFrançois Tigeot 
569c59a5c48SFrançois Tigeot 	}
570c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("%d %d\n", dig_enc->dig_encoder, primary->offset);
571c59a5c48SFrançois Tigeot }
572c59a5c48SFrançois Tigeot 
573c59a5c48SFrançois Tigeot static void
radeon_mst_encoder_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)574c59a5c48SFrançois Tigeot radeon_mst_encoder_mode_set(struct drm_encoder *encoder,
575c59a5c48SFrançois Tigeot 			     struct drm_display_mode *mode,
576c59a5c48SFrançois Tigeot 			     struct drm_display_mode *adjusted_mode)
577c59a5c48SFrançois Tigeot {
578c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("\n");
579c59a5c48SFrançois Tigeot }
580c59a5c48SFrançois Tigeot 
radeon_mst_encoder_commit(struct drm_encoder * encoder)581c59a5c48SFrançois Tigeot static void radeon_mst_encoder_commit(struct drm_encoder *encoder)
582c59a5c48SFrançois Tigeot {
583c59a5c48SFrançois Tigeot 	radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
584c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("\n");
585c59a5c48SFrançois Tigeot }
586c59a5c48SFrançois Tigeot 
587c59a5c48SFrançois Tigeot static const struct drm_encoder_helper_funcs radeon_mst_helper_funcs = {
588c59a5c48SFrançois Tigeot 	.dpms = radeon_mst_encoder_dpms,
589c59a5c48SFrançois Tigeot 	.mode_fixup = radeon_mst_mode_fixup,
590c59a5c48SFrançois Tigeot 	.prepare = radeon_mst_encoder_prepare,
591c59a5c48SFrançois Tigeot 	.mode_set = radeon_mst_encoder_mode_set,
592c59a5c48SFrançois Tigeot 	.commit = radeon_mst_encoder_commit,
593c59a5c48SFrançois Tigeot };
594c59a5c48SFrançois Tigeot 
radeon_dp_mst_encoder_destroy(struct drm_encoder * encoder)595c59a5c48SFrançois Tigeot static void radeon_dp_mst_encoder_destroy(struct drm_encoder *encoder)
596c59a5c48SFrançois Tigeot {
597c59a5c48SFrançois Tigeot 	drm_encoder_cleanup(encoder);
598c59a5c48SFrançois Tigeot 	kfree(encoder);
599c59a5c48SFrançois Tigeot }
600c59a5c48SFrançois Tigeot 
601c59a5c48SFrançois Tigeot static const struct drm_encoder_funcs radeon_dp_mst_enc_funcs = {
602c59a5c48SFrançois Tigeot 	.destroy = radeon_dp_mst_encoder_destroy,
603c59a5c48SFrançois Tigeot };
604c59a5c48SFrançois Tigeot 
605c59a5c48SFrançois Tigeot static struct radeon_encoder *
radeon_dp_create_fake_mst_encoder(struct radeon_connector * connector)606c59a5c48SFrançois Tigeot radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector)
607c59a5c48SFrançois Tigeot {
608c59a5c48SFrançois Tigeot 	struct drm_device *dev = connector->base.dev;
609c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
610c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
611c59a5c48SFrançois Tigeot 	struct radeon_encoder_mst *mst_enc;
612c59a5c48SFrançois Tigeot 	struct drm_encoder *encoder;
613c59a5c48SFrançois Tigeot 	const struct drm_connector_helper_funcs *connector_funcs = connector->base.helper_private;
614c59a5c48SFrançois Tigeot 	struct drm_encoder *enc_master = connector_funcs->best_encoder(&connector->base);
615c59a5c48SFrançois Tigeot 
616c59a5c48SFrançois Tigeot 	DRM_DEBUG_KMS("enc master is %p\n", enc_master);
617c59a5c48SFrançois Tigeot 	radeon_encoder = kzalloc(sizeof(*radeon_encoder), GFP_KERNEL);
618c59a5c48SFrançois Tigeot 	if (!radeon_encoder)
619c59a5c48SFrançois Tigeot 		return NULL;
620c59a5c48SFrançois Tigeot 
621c59a5c48SFrançois Tigeot 	radeon_encoder->enc_priv = kzalloc(sizeof(*mst_enc), GFP_KERNEL);
622c59a5c48SFrançois Tigeot 	if (!radeon_encoder->enc_priv) {
623c59a5c48SFrançois Tigeot 		kfree(radeon_encoder);
624c59a5c48SFrançois Tigeot 		return NULL;
625c59a5c48SFrançois Tigeot 	}
626c59a5c48SFrançois Tigeot 	encoder = &radeon_encoder->base;
627c59a5c48SFrançois Tigeot 	switch (rdev->num_crtc) {
628c59a5c48SFrançois Tigeot 	case 1:
629c59a5c48SFrançois Tigeot 		encoder->possible_crtcs = 0x1;
630c59a5c48SFrançois Tigeot 		break;
631c59a5c48SFrançois Tigeot 	case 2:
632c59a5c48SFrançois Tigeot 	default:
633c59a5c48SFrançois Tigeot 		encoder->possible_crtcs = 0x3;
634c59a5c48SFrançois Tigeot 		break;
635c59a5c48SFrançois Tigeot 	case 4:
636c59a5c48SFrançois Tigeot 		encoder->possible_crtcs = 0xf;
637c59a5c48SFrançois Tigeot 		break;
638c59a5c48SFrançois Tigeot 	case 6:
639c59a5c48SFrançois Tigeot 		encoder->possible_crtcs = 0x3f;
640c59a5c48SFrançois Tigeot 		break;
641c59a5c48SFrançois Tigeot 	}
642c59a5c48SFrançois Tigeot 
643c59a5c48SFrançois Tigeot 	drm_encoder_init(dev, &radeon_encoder->base, &radeon_dp_mst_enc_funcs,
644c59a5c48SFrançois Tigeot 			 DRM_MODE_ENCODER_DPMST, NULL);
645c59a5c48SFrançois Tigeot 	drm_encoder_helper_add(encoder, &radeon_mst_helper_funcs);
646c59a5c48SFrançois Tigeot 
647c59a5c48SFrançois Tigeot 	mst_enc = radeon_encoder->enc_priv;
648c59a5c48SFrançois Tigeot 	mst_enc->connector = connector;
649c59a5c48SFrançois Tigeot 	mst_enc->primary = to_radeon_encoder(enc_master);
650c59a5c48SFrançois Tigeot 	radeon_encoder->is_mst_encoder = true;
651c59a5c48SFrançois Tigeot 	return radeon_encoder;
652c59a5c48SFrançois Tigeot }
653c59a5c48SFrançois Tigeot 
654c59a5c48SFrançois Tigeot int
radeon_dp_mst_init(struct radeon_connector * radeon_connector)655c59a5c48SFrançois Tigeot radeon_dp_mst_init(struct radeon_connector *radeon_connector)
656c59a5c48SFrançois Tigeot {
657c59a5c48SFrançois Tigeot 	struct drm_device *dev = radeon_connector->base.dev;
658c59a5c48SFrançois Tigeot 
659c59a5c48SFrançois Tigeot 	if (!radeon_connector->ddc_bus->has_aux)
660c59a5c48SFrançois Tigeot 		return 0;
661c59a5c48SFrançois Tigeot 
662c59a5c48SFrançois Tigeot 	radeon_connector->mst_mgr.cbs = &mst_cbs;
663*a85cb24fSFrançois Tigeot 	return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev,
664c59a5c48SFrançois Tigeot 					    &radeon_connector->ddc_bus->aux, 16, 6,
665c59a5c48SFrançois Tigeot 					    radeon_connector->base.base.id);
666c59a5c48SFrançois Tigeot }
667c59a5c48SFrançois Tigeot 
668c59a5c48SFrançois Tigeot int
radeon_dp_mst_probe(struct radeon_connector * radeon_connector)669c59a5c48SFrançois Tigeot radeon_dp_mst_probe(struct radeon_connector *radeon_connector)
670c59a5c48SFrançois Tigeot {
671c59a5c48SFrançois Tigeot 	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
672c59a5c48SFrançois Tigeot 	struct drm_device *dev = radeon_connector->base.dev;
673c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
674c59a5c48SFrançois Tigeot 	int ret;
675c59a5c48SFrançois Tigeot 	u8 msg[1];
676c59a5c48SFrançois Tigeot 
677c59a5c48SFrançois Tigeot 	if (!radeon_mst)
678c59a5c48SFrançois Tigeot 		return 0;
679c59a5c48SFrançois Tigeot 
680c59a5c48SFrançois Tigeot 	if (!ASIC_IS_DCE5(rdev))
681c59a5c48SFrançois Tigeot 		return 0;
682c59a5c48SFrançois Tigeot 
683c59a5c48SFrançois Tigeot 	if (dig_connector->dpcd[DP_DPCD_REV] < 0x12)
684c59a5c48SFrançois Tigeot 		return 0;
685c59a5c48SFrançois Tigeot 
686c59a5c48SFrançois Tigeot 	ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_MSTM_CAP, msg,
687c59a5c48SFrançois Tigeot 			       1);
688c59a5c48SFrançois Tigeot 	if (ret) {
689c59a5c48SFrançois Tigeot 		if (msg[0] & DP_MST_CAP) {
690c59a5c48SFrançois Tigeot 			DRM_DEBUG_KMS("Sink is MST capable\n");
691c59a5c48SFrançois Tigeot 			dig_connector->is_mst = true;
692c59a5c48SFrançois Tigeot 		} else {
693c59a5c48SFrançois Tigeot 			DRM_DEBUG_KMS("Sink is not MST capable\n");
694c59a5c48SFrançois Tigeot 			dig_connector->is_mst = false;
695c59a5c48SFrançois Tigeot 		}
696c59a5c48SFrançois Tigeot 
697c59a5c48SFrançois Tigeot 	}
698c59a5c48SFrançois Tigeot 	drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr,
699c59a5c48SFrançois Tigeot 					dig_connector->is_mst);
700c59a5c48SFrançois Tigeot 	return dig_connector->is_mst;
701c59a5c48SFrançois Tigeot }
702c59a5c48SFrançois Tigeot 
703c59a5c48SFrançois Tigeot int
radeon_dp_mst_check_status(struct radeon_connector * radeon_connector)704c59a5c48SFrançois Tigeot radeon_dp_mst_check_status(struct radeon_connector *radeon_connector)
705c59a5c48SFrançois Tigeot {
706c59a5c48SFrançois Tigeot 	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
707c59a5c48SFrançois Tigeot 	int retry;
708c59a5c48SFrançois Tigeot 
709c59a5c48SFrançois Tigeot 	if (dig_connector->is_mst) {
710c59a5c48SFrançois Tigeot 		u8 esi[16] = { 0 };
711c59a5c48SFrançois Tigeot 		int dret;
712c59a5c48SFrançois Tigeot 		int ret = 0;
713c59a5c48SFrançois Tigeot 		bool handled;
714c59a5c48SFrançois Tigeot 
715c59a5c48SFrançois Tigeot 		dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux,
716c59a5c48SFrançois Tigeot 				       DP_SINK_COUNT_ESI, esi, 8);
717c59a5c48SFrançois Tigeot go_again:
718c59a5c48SFrançois Tigeot 		if (dret == 8) {
719c59a5c48SFrançois Tigeot 			DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]);
720c59a5c48SFrançois Tigeot 			ret = drm_dp_mst_hpd_irq(&radeon_connector->mst_mgr, esi, &handled);
721c59a5c48SFrançois Tigeot 
722c59a5c48SFrançois Tigeot 			if (handled) {
723c59a5c48SFrançois Tigeot 				for (retry = 0; retry < 3; retry++) {
724c59a5c48SFrançois Tigeot 					int wret;
725c59a5c48SFrançois Tigeot 					wret = drm_dp_dpcd_write(&radeon_connector->ddc_bus->aux,
726c59a5c48SFrançois Tigeot 								 DP_SINK_COUNT_ESI + 1, &esi[1], 3);
727c59a5c48SFrançois Tigeot 					if (wret == 3)
728c59a5c48SFrançois Tigeot 						break;
729c59a5c48SFrançois Tigeot 				}
730c59a5c48SFrançois Tigeot 
731c59a5c48SFrançois Tigeot 				dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux,
732c59a5c48SFrançois Tigeot 							DP_SINK_COUNT_ESI, esi, 8);
733c59a5c48SFrançois Tigeot 				if (dret == 8) {
734c59a5c48SFrançois Tigeot 					DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]);
735c59a5c48SFrançois Tigeot 					goto go_again;
736c59a5c48SFrançois Tigeot 				}
737c59a5c48SFrançois Tigeot 			} else
738c59a5c48SFrançois Tigeot 				ret = 0;
739c59a5c48SFrançois Tigeot 
740c59a5c48SFrançois Tigeot 			return ret;
741c59a5c48SFrançois Tigeot 		} else {
742c59a5c48SFrançois Tigeot 			DRM_DEBUG_KMS("failed to get ESI - device may have failed %d\n", ret);
743c59a5c48SFrançois Tigeot 			dig_connector->is_mst = false;
744c59a5c48SFrançois Tigeot 			drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr,
745c59a5c48SFrançois Tigeot 							dig_connector->is_mst);
746c59a5c48SFrançois Tigeot 			/* send a hotplug event */
747c59a5c48SFrançois Tigeot 		}
748c59a5c48SFrançois Tigeot 	}
749c59a5c48SFrançois Tigeot 	return -EINVAL;
750c59a5c48SFrançois Tigeot }
751c59a5c48SFrançois Tigeot 
752c59a5c48SFrançois Tigeot #if defined(CONFIG_DEBUG_FS)
753c59a5c48SFrançois Tigeot 
radeon_debugfs_mst_info(struct seq_file * m,void * data)754c59a5c48SFrançois Tigeot static int radeon_debugfs_mst_info(struct seq_file *m, void *data)
755c59a5c48SFrançois Tigeot {
756c59a5c48SFrançois Tigeot 	struct drm_info_node *node = (struct drm_info_node *)m->private;
757c59a5c48SFrançois Tigeot 	struct drm_device *dev = node->minor->dev;
758c59a5c48SFrançois Tigeot 	struct drm_connector *connector;
759c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector;
760c59a5c48SFrançois Tigeot 	struct radeon_connector_atom_dig *dig_connector;
761c59a5c48SFrançois Tigeot 	int i;
762c59a5c48SFrançois Tigeot 
763c59a5c48SFrançois Tigeot 	drm_modeset_lock_all(dev);
764c59a5c48SFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
765c59a5c48SFrançois Tigeot 		if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
766c59a5c48SFrançois Tigeot 			continue;
767c59a5c48SFrançois Tigeot 
768c59a5c48SFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
769c59a5c48SFrançois Tigeot 		dig_connector = radeon_connector->con_priv;
770c59a5c48SFrançois Tigeot 		if (radeon_connector->is_mst_connector)
771c59a5c48SFrançois Tigeot 			continue;
772c59a5c48SFrançois Tigeot 		if (!dig_connector->is_mst)
773c59a5c48SFrançois Tigeot 			continue;
774c59a5c48SFrançois Tigeot 		drm_dp_mst_dump_topology(m, &radeon_connector->mst_mgr);
775c59a5c48SFrançois Tigeot 
776c59a5c48SFrançois Tigeot 		for (i = 0; i < radeon_connector->enabled_attribs; i++)
777c59a5c48SFrançois Tigeot 			seq_printf(m, "attrib %d: %d %d\n", i,
778c59a5c48SFrançois Tigeot 				   radeon_connector->cur_stream_attribs[i].fe,
779c59a5c48SFrançois Tigeot 				   radeon_connector->cur_stream_attribs[i].slots);
780c59a5c48SFrançois Tigeot 	}
781c59a5c48SFrançois Tigeot 	drm_modeset_unlock_all(dev);
782c59a5c48SFrançois Tigeot 	return 0;
783c59a5c48SFrançois Tigeot }
784c59a5c48SFrançois Tigeot 
785c59a5c48SFrançois Tigeot static struct drm_info_list radeon_debugfs_mst_list[] = {
786c59a5c48SFrançois Tigeot 	{"radeon_mst_info", &radeon_debugfs_mst_info, 0, NULL},
787c59a5c48SFrançois Tigeot };
788c59a5c48SFrançois Tigeot #endif
789c59a5c48SFrançois Tigeot 
radeon_mst_debugfs_init(struct radeon_device * rdev)790c59a5c48SFrançois Tigeot int radeon_mst_debugfs_init(struct radeon_device *rdev)
791c59a5c48SFrançois Tigeot {
792c59a5c48SFrançois Tigeot #if defined(CONFIG_DEBUG_FS)
793c59a5c48SFrançois Tigeot 	return radeon_debugfs_add_files(rdev, radeon_debugfs_mst_list, 1);
794c59a5c48SFrançois Tigeot #endif
795c59a5c48SFrançois Tigeot 	return 0;
796c59a5c48SFrançois Tigeot }
797