Skip to content

Commit 8663bc7

Browse files
author
Ben Skeggs
committed
drm/nouveau/dp: move all nv50/sor-specific code out of nouveau_dp.c
Off-chip encoders (which we don't support yet anyway), and newer chipsets (such as NVD9...), will need their own code for this. Signed-off-by: Ben Skeggs <[email protected]>
1 parent 8c1dcb6 commit 8663bc7

File tree

5 files changed

+231
-228
lines changed

5 files changed

+231
-228
lines changed

drivers/gpu/drm/nouveau/nouveau_dp.c

Lines changed: 16 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -161,116 +161,6 @@ auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size)
161161
return ret;
162162
}
163163

164-
static u32
165-
dp_link_bw_get(struct drm_device *dev, int or, int link)
166-
{
167-
u32 ctrl = nv_rd32(dev, 0x614300 + (or * 0x800));
168-
if (!(ctrl & 0x000c0000))
169-
return 162000;
170-
return 270000;
171-
}
172-
173-
static int
174-
dp_lane_count_get(struct drm_device *dev, int or, int link)
175-
{
176-
u32 ctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
177-
switch (ctrl & 0x000f0000) {
178-
case 0x00010000: return 1;
179-
case 0x00030000: return 2;
180-
default:
181-
return 4;
182-
}
183-
}
184-
185-
void
186-
nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp)
187-
{
188-
const u32 symbol = 100000;
189-
int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
190-
int TU, VTUi, VTUf, VTUa;
191-
u64 link_data_rate, link_ratio, unk;
192-
u32 best_diff = 64 * symbol;
193-
u32 link_nr, link_bw, r;
194-
195-
/* calculate packed data rate for each lane */
196-
link_nr = dp_lane_count_get(dev, or, link);
197-
link_data_rate = (clk * bpp / 8) / link_nr;
198-
199-
/* calculate ratio of packed data rate to link symbol rate */
200-
link_bw = dp_link_bw_get(dev, or, link);
201-
link_ratio = link_data_rate * symbol;
202-
r = do_div(link_ratio, link_bw);
203-
204-
for (TU = 64; TU >= 32; TU--) {
205-
/* calculate average number of valid symbols in each TU */
206-
u32 tu_valid = link_ratio * TU;
207-
u32 calc, diff;
208-
209-
/* find a hw representation for the fraction.. */
210-
VTUi = tu_valid / symbol;
211-
calc = VTUi * symbol;
212-
diff = tu_valid - calc;
213-
if (diff) {
214-
if (diff >= (symbol / 2)) {
215-
VTUf = symbol / (symbol - diff);
216-
if (symbol - (VTUf * diff))
217-
VTUf++;
218-
219-
if (VTUf <= 15) {
220-
VTUa = 1;
221-
calc += symbol - (symbol / VTUf);
222-
} else {
223-
VTUa = 0;
224-
VTUf = 1;
225-
calc += symbol;
226-
}
227-
} else {
228-
VTUa = 0;
229-
VTUf = min((int)(symbol / diff), 15);
230-
calc += symbol / VTUf;
231-
}
232-
233-
diff = calc - tu_valid;
234-
} else {
235-
/* no remainder, but the hw doesn't like the fractional
236-
* part to be zero. decrement the integer part and
237-
* have the fraction add a whole symbol back
238-
*/
239-
VTUa = 0;
240-
VTUf = 1;
241-
VTUi--;
242-
}
243-
244-
if (diff < best_diff) {
245-
best_diff = diff;
246-
bestTU = TU;
247-
bestVTUa = VTUa;
248-
bestVTUf = VTUf;
249-
bestVTUi = VTUi;
250-
if (diff == 0)
251-
break;
252-
}
253-
}
254-
255-
if (!bestTU) {
256-
NV_ERROR(dev, "DP: unable to find suitable config\n");
257-
return;
258-
}
259-
260-
/* XXX close to vbios numbers, but not right */
261-
unk = (symbol - link_ratio) * bestTU;
262-
unk *= link_ratio;
263-
r = do_div(unk, symbol);
264-
r = do_div(unk, symbol);
265-
unk += 6;
266-
267-
nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2);
268-
nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 |
269-
bestVTUf << 16 |
270-
bestVTUi << 8 |
271-
unk);
272-
}
273-
274164
u8 *
275165
nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
276166
{
@@ -318,13 +208,10 @@ nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
318208
* link training
319209
*****************************************************************************/
320210
struct dp_state {
211+
struct dp_train_func *func;
321212
struct dcb_entry *dcb;
322-
u8 *table;
323-
u8 *entry;
324213
int auxch;
325214
int crtc;
326-
int or;
327-
int link;
328215
u8 *dpcd;
329216
int link_nr;
330217
u32 link_bw;
@@ -335,142 +222,58 @@ struct dp_state {
335222
static void
336223
dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
337224
{
338-
int or = dp->or, link = dp->link;
339-
u8 *entry, sink[2];
340-
u32 dp_ctrl;
341-
u16 script;
225+
u8 sink[2];
342226

343227
NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
344228

345-
/* set selected link rate on source */
346-
switch (dp->link_bw) {
347-
case 270000:
348-
nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00040000);
349-
sink[0] = DP_LINK_BW_2_7;
350-
break;
351-
default:
352-
nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00000000);
353-
sink[0] = DP_LINK_BW_1_62;
354-
break;
355-
}
356-
357-
/* offset +0x0a of each dp encoder table entry is a pointer to another
358-
* table, that has (among other things) pointers to more scripts that
359-
* need to be executed, this time depending on link speed.
360-
*/
361-
entry = ROMPTR(dev, dp->entry[10]);
362-
if (entry) {
363-
if (dp->table[0] < 0x30) {
364-
while (dp->link_bw < (ROM16(entry[0]) * 10))
365-
entry += 4;
366-
script = ROM16(entry[2]);
367-
} else {
368-
while (dp->link_bw < (entry[0] * 27000))
369-
entry += 3;
370-
script = ROM16(entry[1]);
371-
}
229+
/* set desired link configuration on the source */
230+
dp->func->link_set(dev, dp->dcb, dp->crtc, dp->link_nr, dp->link_bw,
231+
dp->dpcd[2] & DP_ENHANCED_FRAME_CAP);
372232

373-
nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
374-
}
375-
376-
/* configure lane count on the source */
377-
dp_ctrl = ((1 << dp->link_nr) - 1) << 16;
233+
/* inform the sink of the new configuration */
234+
sink[0] = dp->link_bw / 27000;
378235
sink[1] = dp->link_nr;
379-
if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) {
380-
dp_ctrl |= 0x00004000;
236+
if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)
381237
sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
382-
}
383-
384-
nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x001f4000, dp_ctrl);
385238

386-
/* inform the sink of the new configuration */
387239
auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2);
388240
}
389241

390242
static void
391-
dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 tp)
243+
dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 pattern)
392244
{
393245
u8 sink_tp;
394246

395-
NV_DEBUG_KMS(dev, "training pattern %d\n", tp);
247+
NV_DEBUG_KMS(dev, "training pattern %d\n", pattern);
396248

397-
nv_mask(dev, NV50_SOR_DP_CTRL(dp->or, dp->link), 0x0f000000, tp << 24);
249+
dp->func->train_set(dev, dp->dcb, pattern);
398250

399251
auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
400252
sink_tp &= ~DP_TRAINING_PATTERN_MASK;
401-
sink_tp |= tp;
253+
sink_tp |= pattern;
402254
auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
403255
}
404256

405-
static const u8 nv50_lane_map[] = { 16, 8, 0, 24 };
406-
static const u8 nvaf_lane_map[] = { 24, 16, 8, 0 };
407-
408257
static int
409258
dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
410259
{
411-
struct drm_nouveau_private *dev_priv = dev->dev_private;
412-
u32 mask = 0, drv = 0, pre = 0, unk = 0;
413-
const u8 *shifts;
414-
int link = dp->link;
415-
int or = dp->or;
416260
int i;
417261

418-
if (dev_priv->chipset != 0xaf)
419-
shifts = nv50_lane_map;
420-
else
421-
shifts = nvaf_lane_map;
422-
423262
for (i = 0; i < dp->link_nr; i++) {
424-
u8 *conf = dp->entry + dp->table[4];
425263
u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
426264
u8 lpre = (lane & 0x0c) >> 2;
427265
u8 lvsw = (lane & 0x03) >> 0;
428266

429-
mask |= 0xff << shifts[i];
430-
unk |= 1 << (shifts[i] >> 3);
431-
432267
dp->conf[i] = (lpre << 3) | lvsw;
433268
if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200)
434269
dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED;
435270
if ((lpre << 3) == DP_TRAIN_PRE_EMPHASIS_9_5)
436271
dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
437272

438273
NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]);
439-
440-
if (dp->table[0] < 0x30) {
441-
u8 *last = conf + (dp->entry[4] * dp->table[5]);
442-
while (lvsw != conf[0] || lpre != conf[1]) {
443-
conf += dp->table[5];
444-
if (conf >= last)
445-
return -EINVAL;
446-
}
447-
448-
conf += 2;
449-
} else {
450-
/* no lookup table anymore, set entries for each
451-
* combination of voltage swing and pre-emphasis
452-
* level allowed by the DP spec.
453-
*/
454-
switch (lvsw) {
455-
case 0: lpre += 0; break;
456-
case 1: lpre += 4; break;
457-
case 2: lpre += 7; break;
458-
case 3: lpre += 9; break;
459-
}
460-
461-
conf = conf + (lpre * dp->table[5]);
462-
conf++;
463-
}
464-
465-
drv |= conf[0] << shifts[i];
466-
pre |= conf[1] << shifts[i];
467-
unk = (unk & ~0x0000ff00) | (conf[2] << 8);
274+
dp->func->train_adj(dev, dp->dcb, i, lvsw, lpre);
468275
}
469276

470-
nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv);
471-
nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, pre);
472-
nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff0f, unk);
473-
474277
return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4);
475278
}
476279

@@ -598,7 +401,8 @@ dp_link_train_fini(struct drm_device *dev, struct dp_state *dp)
598401
}
599402

600403
bool
601-
nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
404+
nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
405+
struct dp_train_func *func)
602406
{
603407
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
604408
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
@@ -614,15 +418,10 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
614418
if (!auxch)
615419
return false;
616420

617-
dp.table = nouveau_dp_bios_data(dev, nv_encoder->dcb, &dp.entry);
618-
if (!dp.table)
619-
return -EINVAL;
620-
421+
dp.func = func;
621422
dp.dcb = nv_encoder->dcb;
622423
dp.crtc = nv_crtc->index;
623424
dp.auxch = auxch->drive;
624-
dp.or = nv_encoder->or;
625-
dp.link = !(nv_encoder->dcb->sorconf.link & 1);
626425
dp.dpcd = nv_encoder->dp.dpcd;
627426

628427
/* some sinks toggle hotplug in response to some of the actions

drivers/gpu/drm/nouveau/nouveau_drv.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,14 +1162,6 @@ int nouveau_ttm_mmap(struct file *, struct vm_area_struct *);
11621162
/* nouveau_hdmi.c */
11631163
void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *);
11641164

1165-
/* nouveau_dp.c */
1166-
int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
1167-
uint8_t *data, int data_nr);
1168-
bool nouveau_dp_detect(struct drm_encoder *);
1169-
bool nouveau_dp_link_train(struct drm_encoder *, u32 datarate);
1170-
void nouveau_dp_tu_update(struct drm_device *, int, int, u32, u32);
1171-
u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **);
1172-
11731165
/* nv04_fb.c */
11741166
extern int nv04_fb_vram_init(struct drm_device *);
11751167
extern int nv04_fb_init(struct drm_device *);

drivers/gpu/drm/nouveau/nouveau_encoder.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@
3232

3333
#define NV_DPMS_CLEARED 0x80
3434

35+
struct dp_train_func {
36+
void (*link_set)(struct drm_device *, struct dcb_entry *, int crtc,
37+
int nr, u32 bw, bool enhframe);
38+
void (*train_set)(struct drm_device *, struct dcb_entry *, u8 pattern);
39+
void (*train_adj)(struct drm_device *, struct dcb_entry *,
40+
u8 lane, u8 swing, u8 preem);
41+
};
42+
3543
struct nouveau_encoder {
3644
struct drm_encoder_slave base;
3745

@@ -78,9 +86,19 @@ get_slave_funcs(struct drm_encoder *enc)
7886
return to_encoder_slave(enc)->slave_funcs;
7987
}
8088

89+
/* nouveau_dp.c */
90+
int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
91+
uint8_t *data, int data_nr);
92+
bool nouveau_dp_detect(struct drm_encoder *);
93+
bool nouveau_dp_link_train(struct drm_encoder *, u32 datarate,
94+
struct dp_train_func *);
95+
u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **);
96+
8197
struct nouveau_connector *
8298
nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
8399
int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
100+
void nv50_sor_dp_calc_tu(struct drm_device *, int, int, u32, u32);
84101
int nv50_dac_create(struct drm_connector *, struct dcb_entry *);
85102

103+
86104
#endif /* __NOUVEAU_ENCODER_H__ */

drivers/gpu/drm/nouveau/nv50_display.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,9 +863,9 @@ nv50_display_unk20_handler(struct drm_device *dev)
863863
if (type == OUTPUT_DP) {
864864
int link = !(dcb->dpconf.sor.link & 1);
865865
if ((mc & 0x000f0000) == 0x00020000)
866-
nouveau_dp_tu_update(dev, or, link, pclk, 18);
866+
nv50_sor_dp_calc_tu(dev, or, link, pclk, 18);
867867
else
868-
nouveau_dp_tu_update(dev, or, link, pclk, 24);
868+
nv50_sor_dp_calc_tu(dev, or, link, pclk, 24);
869869
}
870870

871871
if (dcb->type != OUTPUT_ANALOG) {

0 commit comments

Comments
 (0)