2 * Copyright 2013 Red Hat Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
28 #include <subdev/bios.h>
29 #include <subdev/bios/init.h>
30 #include <subdev/i2c.h>
32 #include <nvif/class.h>
34 /******************************************************************************
36 *****************************************************************************/
38 struct nvkm_output_dp
*outp
;
49 dp_set_link_config(struct dp_state
*dp
)
51 struct nvkm_output_dp
*outp
= dp
->outp
;
52 struct nvkm_disp
*disp
= outp
->base
.disp
;
53 struct nvkm_subdev
*subdev
= &disp
->engine
.subdev
;
54 struct nvkm_bios
*bios
= subdev
->device
->bios
;
55 struct nvbios_init init
= {
59 .outp
= &outp
->base
.info
,
67 OUTP_DBG(&outp
->base
, "%d lanes at %d KB/s", dp
->link_nr
, dp
->link_bw
);
69 /* set desired link configuration on the source */
70 if ((lnkcmp
= dp
->outp
->info
.lnkcmp
)) {
71 if (outp
->version
< 0x30) {
72 while ((dp
->link_bw
/ 10) < nvbios_rd16(bios
, lnkcmp
))
74 init
.offset
= nvbios_rd16(bios
, lnkcmp
+ 2);
76 while ((dp
->link_bw
/ 27000) < nvbios_rd08(bios
, lnkcmp
))
78 init
.offset
= nvbios_rd16(bios
, lnkcmp
+ 1);
84 ret
= outp
->func
->lnk_ctl(outp
, dp
->link_nr
, dp
->link_bw
/ 27000,
85 outp
->dpcd
[DPCD_RC02
] &
86 DPCD_RC02_ENHANCED_FRAME_CAP
);
89 OUTP_ERR(&outp
->base
, "lnk_ctl failed with %d", ret
);
93 outp
->func
->lnk_pwr(outp
, dp
->link_nr
);
95 /* set desired link configuration on the sink */
96 sink
[0] = dp
->link_bw
/ 27000;
97 sink
[1] = dp
->link_nr
;
98 if (outp
->dpcd
[DPCD_RC02
] & DPCD_RC02_ENHANCED_FRAME_CAP
)
99 sink
[1] |= DPCD_LC01_ENHANCED_FRAME_EN
;
101 return nvkm_wraux(outp
->aux
, DPCD_LC00_LINK_BW_SET
, sink
, 2);
105 dp_set_training_pattern(struct dp_state
*dp
, u8 pattern
)
107 struct nvkm_output_dp
*outp
= dp
->outp
;
110 OUTP_DBG(&outp
->base
, "training pattern %d", pattern
);
111 outp
->func
->pattern(outp
, pattern
);
113 nvkm_rdaux(outp
->aux
, DPCD_LC02
, &sink_tp
, 1);
114 sink_tp
&= ~DPCD_LC02_TRAINING_PATTERN_SET
;
116 nvkm_wraux(outp
->aux
, DPCD_LC02
, &sink_tp
, 1);
120 dp_link_train_commit(struct dp_state
*dp
, bool pc
)
122 struct nvkm_output_dp
*outp
= dp
->outp
;
125 for (i
= 0; i
< dp
->link_nr
; i
++) {
126 u8 lane
= (dp
->stat
[4 + (i
>> 1)] >> ((i
& 1) * 4)) & 0xf;
127 u8 lpc2
= (dp
->pc2stat
>> (i
* 2)) & 0x3;
128 u8 lpre
= (lane
& 0x0c) >> 2;
129 u8 lvsw
= (lane
& 0x03) >> 0;
135 lpc2
= hipc
| DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED
;
137 lpre
= hipe
| DPCD_LC03_MAX_SWING_REACHED
; /* yes. */
138 lvsw
= hivs
= 3 - (lpre
& 3);
141 lvsw
= hivs
| DPCD_LC03_MAX_SWING_REACHED
;
144 dp
->conf
[i
] = (lpre
<< 3) | lvsw
;
145 dp
->pc2conf
[i
>> 1] |= lpc2
<< ((i
& 1) * 4);
147 OUTP_DBG(&outp
->base
, "config lane %d %02x %02x",
148 i
, dp
->conf
[i
], lpc2
);
149 outp
->func
->drv_ctl(outp
, i
, lvsw
& 3, lpre
& 3, lpc2
& 3);
152 ret
= nvkm_wraux(outp
->aux
, DPCD_LC03(0), dp
->conf
, 4);
157 ret
= nvkm_wraux(outp
->aux
, DPCD_LC0F
, dp
->pc2conf
, 2);
166 dp_link_train_update(struct dp_state
*dp
, bool pc
, u32 delay
)
168 struct nvkm_output_dp
*outp
= dp
->outp
;
171 if (outp
->dpcd
[DPCD_RC0E_AUX_RD_INTERVAL
])
172 mdelay(outp
->dpcd
[DPCD_RC0E_AUX_RD_INTERVAL
] * 4);
176 ret
= nvkm_rdaux(outp
->aux
, DPCD_LS02
, dp
->stat
, 6);
181 ret
= nvkm_rdaux(outp
->aux
, DPCD_LS0C
, &dp
->pc2stat
, 1);
184 OUTP_DBG(&outp
->base
, "status %6ph pc2 %02x",
185 dp
->stat
, dp
->pc2stat
);
187 OUTP_DBG(&outp
->base
, "status %6ph", dp
->stat
);
194 dp_link_train_cr(struct dp_state
*dp
)
196 bool cr_done
= false, abort
= false;
197 int voltage
= dp
->conf
[0] & DPCD_LC03_VOLTAGE_SWING_SET
;
200 dp_set_training_pattern(dp
, 1);
203 if (dp_link_train_commit(dp
, false) ||
204 dp_link_train_update(dp
, false, 100))
208 for (i
= 0; i
< dp
->link_nr
; i
++) {
209 u8 lane
= (dp
->stat
[i
>> 1] >> ((i
& 1) * 4)) & 0xf;
210 if (!(lane
& DPCD_LS02_LANE0_CR_DONE
)) {
212 if (dp
->conf
[i
] & DPCD_LC03_MAX_SWING_REACHED
)
218 if ((dp
->conf
[0] & DPCD_LC03_VOLTAGE_SWING_SET
) != voltage
) {
219 voltage
= dp
->conf
[0] & DPCD_LC03_VOLTAGE_SWING_SET
;
222 } while (!cr_done
&& !abort
&& ++tries
< 5);
224 return cr_done
? 0 : -1;
228 dp_link_train_eq(struct dp_state
*dp
)
230 struct nvkm_output_dp
*outp
= dp
->outp
;
231 bool eq_done
= false, cr_done
= true;
234 if (outp
->dpcd
[2] & DPCD_RC02_TPS3_SUPPORTED
)
235 dp_set_training_pattern(dp
, 3);
237 dp_set_training_pattern(dp
, 2);
241 dp_link_train_commit(dp
, dp
->pc2
)) ||
242 dp_link_train_update(dp
, dp
->pc2
, 400))
245 eq_done
= !!(dp
->stat
[2] & DPCD_LS04_INTERLANE_ALIGN_DONE
);
246 for (i
= 0; i
< dp
->link_nr
&& eq_done
; i
++) {
247 u8 lane
= (dp
->stat
[i
>> 1] >> ((i
& 1) * 4)) & 0xf;
248 if (!(lane
& DPCD_LS02_LANE0_CR_DONE
))
250 if (!(lane
& DPCD_LS02_LANE0_CHANNEL_EQ_DONE
) ||
251 !(lane
& DPCD_LS02_LANE0_SYMBOL_LOCKED
))
254 } while (!eq_done
&& cr_done
&& ++tries
<= 5);
256 return eq_done
? 0 : -1;
260 dp_link_train_init(struct dp_state
*dp
, bool spread
)
262 struct nvkm_output_dp
*outp
= dp
->outp
;
263 struct nvkm_disp
*disp
= outp
->base
.disp
;
264 struct nvkm_subdev
*subdev
= &disp
->engine
.subdev
;
265 struct nvbios_init init
= {
267 .bios
= subdev
->device
->bios
,
268 .outp
= &outp
->base
.info
,
273 /* set desired spread */
275 init
.offset
= outp
->info
.script
[2];
277 init
.offset
= outp
->info
.script
[3];
280 /* pre-train script */
281 init
.offset
= outp
->info
.script
[0];
286 dp_link_train_fini(struct dp_state
*dp
)
288 struct nvkm_output_dp
*outp
= dp
->outp
;
289 struct nvkm_disp
*disp
= outp
->base
.disp
;
290 struct nvkm_subdev
*subdev
= &disp
->engine
.subdev
;
291 struct nvbios_init init
= {
293 .bios
= subdev
->device
->bios
,
294 .outp
= &outp
->base
.info
,
299 /* post-train script */
300 init
.offset
= outp
->info
.script
[1],
304 static const struct dp_rates
{
308 } nvkm_dp_rates
[] = {
309 { 2160000, 0x14, 4 },
310 { 1080000, 0x0a, 4 },
311 { 1080000, 0x14, 2 },
322 nvkm_dp_train(struct work_struct
*w
)
324 struct nvkm_output_dp
*outp
= container_of(w
, typeof(*outp
), lt
.work
);
325 struct nv50_disp
*disp
= nv50_disp(outp
->base
.disp
);
326 const struct dp_rates
*cfg
= nvkm_dp_rates
;
327 struct dp_state _dp
= {
333 if (!outp
->base
.info
.location
&& disp
->func
->sor
.magic
)
334 disp
->func
->sor
.magic(&outp
->base
);
336 /* bring capabilities within encoder limits */
337 if (disp
->base
.engine
.subdev
.device
->chipset
< 0xd0)
338 outp
->dpcd
[2] &= ~DPCD_RC02_TPS3_SUPPORTED
;
339 if ((outp
->dpcd
[2] & 0x1f) > outp
->base
.info
.dpconf
.link_nr
) {
340 outp
->dpcd
[2] &= ~DPCD_RC02_MAX_LANE_COUNT
;
341 outp
->dpcd
[2] |= outp
->base
.info
.dpconf
.link_nr
;
343 if (outp
->dpcd
[1] > outp
->base
.info
.dpconf
.link_bw
)
344 outp
->dpcd
[1] = outp
->base
.info
.dpconf
.link_bw
;
345 dp
->pc2
= outp
->dpcd
[2] & DPCD_RC02_TPS3_SUPPORTED
;
347 /* restrict link config to the lowest required rate, if requested */
349 datarate
= (datarate
/ 8) * 10; /* 8B/10B coding overhead */
350 while (cfg
[1].rate
>= datarate
)
355 /* disable link interrupt handling during link training */
356 nvkm_notify_put(&outp
->irq
);
358 /* enable down-spreading and execute pre-train script from vbios */
359 dp_link_train_init(dp
, outp
->dpcd
[3] & 0x01);
361 while (ret
= -EIO
, (++cfg
)->rate
) {
362 /* select next configuration supported by encoder and sink */
363 while (cfg
->nr
> (outp
->dpcd
[2] & DPCD_RC02_MAX_LANE_COUNT
) ||
364 cfg
->bw
> (outp
->dpcd
[DPCD_RC01_MAX_LINK_RATE
]))
366 dp
->link_bw
= cfg
->bw
* 27000;
367 dp
->link_nr
= cfg
->nr
;
369 /* program selected link configuration */
370 ret
= dp_set_link_config(dp
);
372 /* attempt to train the link at this configuration */
373 memset(dp
->stat
, 0x00, sizeof(dp
->stat
));
374 if (!dp_link_train_cr(dp
) &&
375 !dp_link_train_eq(dp
))
379 /* dp_set_link_config() handled training, or
380 * we failed to communicate with the sink.
386 /* finish link training and execute post-train script from vbios */
387 dp_set_training_pattern(dp
, 0);
389 OUTP_ERR(&outp
->base
, "link training failed");
391 dp_link_train_fini(dp
);
393 /* signal completion and enable link interrupt handling */
394 OUTP_DBG(&outp
->base
, "training complete");
395 atomic_set(&outp
->lt
.done
, 1);
396 wake_up(&outp
->lt
.wait
);
397 nvkm_notify_get(&outp
->irq
);