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