diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2012-07-10 00:36:38 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2012-10-02 23:12:46 -0400 |
commit | 4196faa8623264b79279a06fd186654c959f2767 (patch) | |
tree | d84bb1e28744a3dfbafc1e9203a2ea1fda43eb86 /drivers/gpu/drm/nouveau/nouveau_dp.c | |
parent | e0996aea4c349ba302b63203b7d5cab6034dbdca (diff) |
drm/nouveau/i2c: port to subdev interfaces
v2/v3: Ben Skeggs <bskeggs@redhat.com>
- fix typo in default bus selection
- fix accidental loss of destructor
v4: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
- fix typo causing incorrect default i2c port settings when no BMP data
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_dp.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_dp.c | 219 |
1 files changed, 16 insertions, 203 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 63c0e827c302..9e18b35803a8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c | |||
@@ -23,143 +23,13 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "drmP.h" | 25 | #include "drmP.h" |
26 | #include "drm_dp_helper.h" | ||
26 | 27 | ||
27 | #include "nouveau_drv.h" | 28 | #include "nouveau_drv.h" |
28 | #include <subdev/i2c.h> | ||
29 | #include "nouveau_connector.h" | 29 | #include "nouveau_connector.h" |
30 | #include "nouveau_encoder.h" | 30 | #include "nouveau_encoder.h" |
31 | #include "nouveau_crtc.h" | 31 | #include "nouveau_crtc.h" |
32 | 32 | ||
33 | /****************************************************************************** | ||
34 | * aux channel util functions | ||
35 | *****************************************************************************/ | ||
36 | #define AUX_DBG(fmt, args...) do { \ | ||
37 | if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_AUXCH) { \ | ||
38 | NV_PRINTK(KERN_DEBUG, dev, "AUXCH(%d): " fmt, ch, ##args); \ | ||
39 | } \ | ||
40 | } while (0) | ||
41 | #define AUX_ERR(fmt, args...) NV_ERROR(dev, "AUXCH(%d): " fmt, ch, ##args) | ||
42 | |||
43 | static void | ||
44 | auxch_fini(struct drm_device *dev, int ch) | ||
45 | { | ||
46 | nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); | ||
47 | } | ||
48 | |||
49 | static int | ||
50 | auxch_init(struct drm_device *dev, int ch) | ||
51 | { | ||
52 | const u32 unksel = 1; /* nfi which to use, or if it matters.. */ | ||
53 | const u32 ureq = unksel ? 0x00100000 : 0x00200000; | ||
54 | const u32 urep = unksel ? 0x01000000 : 0x02000000; | ||
55 | u32 ctrl, timeout; | ||
56 | |||
57 | /* wait up to 1ms for any previous transaction to be done... */ | ||
58 | timeout = 1000; | ||
59 | do { | ||
60 | ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); | ||
61 | udelay(1); | ||
62 | if (!timeout--) { | ||
63 | AUX_ERR("begin idle timeout 0x%08x", ctrl); | ||
64 | return -EBUSY; | ||
65 | } | ||
66 | } while (ctrl & 0x03010000); | ||
67 | |||
68 | /* set some magic, and wait up to 1ms for it to appear */ | ||
69 | nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); | ||
70 | timeout = 1000; | ||
71 | do { | ||
72 | ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); | ||
73 | udelay(1); | ||
74 | if (!timeout--) { | ||
75 | AUX_ERR("magic wait 0x%08x\n", ctrl); | ||
76 | auxch_fini(dev, ch); | ||
77 | return -EBUSY; | ||
78 | } | ||
79 | } while ((ctrl & 0x03000000) != urep); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int | ||
85 | auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size) | ||
86 | { | ||
87 | u32 ctrl, stat, timeout, retries; | ||
88 | u32 xbuf[4] = {}; | ||
89 | int ret, i; | ||
90 | |||
91 | AUX_DBG("%d: 0x%08x %d\n", type, addr, size); | ||
92 | |||
93 | ret = auxch_init(dev, ch); | ||
94 | if (ret) | ||
95 | goto out; | ||
96 | |||
97 | stat = nv_rd32(dev, 0x00e4e8 + (ch * 0x50)); | ||
98 | if (!(stat & 0x10000000)) { | ||
99 | AUX_DBG("sink not detected\n"); | ||
100 | ret = -ENXIO; | ||
101 | goto out; | ||
102 | } | ||
103 | |||
104 | if (!(type & 1)) { | ||
105 | memcpy(xbuf, data, size); | ||
106 | for (i = 0; i < 16; i += 4) { | ||
107 | AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); | ||
108 | nv_wr32(dev, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); | ||
113 | ctrl &= ~0x0001f0ff; | ||
114 | ctrl |= type << 12; | ||
115 | ctrl |= size - 1; | ||
116 | nv_wr32(dev, 0x00e4e0 + (ch * 0x50), addr); | ||
117 | |||
118 | /* retry transaction a number of times on failure... */ | ||
119 | ret = -EREMOTEIO; | ||
120 | for (retries = 0; retries < 32; retries++) { | ||
121 | /* reset, and delay a while if this is a retry */ | ||
122 | nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); | ||
123 | nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); | ||
124 | if (retries) | ||
125 | udelay(400); | ||
126 | |||
127 | /* transaction request, wait up to 1ms for it to complete */ | ||
128 | nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); | ||
129 | |||
130 | timeout = 1000; | ||
131 | do { | ||
132 | ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); | ||
133 | udelay(1); | ||
134 | if (!timeout--) { | ||
135 | AUX_ERR("tx req timeout 0x%08x\n", ctrl); | ||
136 | goto out; | ||
137 | } | ||
138 | } while (ctrl & 0x00010000); | ||
139 | |||
140 | /* read status, and check if transaction completed ok */ | ||
141 | stat = nv_mask(dev, 0x00e4e8 + (ch * 0x50), 0, 0); | ||
142 | if (!(stat & 0x000f0f00)) { | ||
143 | ret = 0; | ||
144 | break; | ||
145 | } | ||
146 | |||
147 | AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); | ||
148 | } | ||
149 | |||
150 | if (type & 1) { | ||
151 | for (i = 0; i < 16; i += 4) { | ||
152 | xbuf[i / 4] = nv_rd32(dev, 0x00e4d0 + (ch * 0x50) + i); | ||
153 | AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); | ||
154 | } | ||
155 | memcpy(data, xbuf, size); | ||
156 | } | ||
157 | |||
158 | out: | ||
159 | auxch_fini(dev, ch); | ||
160 | return ret; | ||
161 | } | ||
162 | |||
163 | u8 * | 33 | u8 * |
164 | nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry) | 34 | nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry) |
165 | { | 35 | { |
@@ -208,9 +78,9 @@ nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry) | |||
208 | * link training | 78 | * link training |
209 | *****************************************************************************/ | 79 | *****************************************************************************/ |
210 | struct dp_state { | 80 | struct dp_state { |
81 | struct nouveau_i2c_port *auxch; | ||
211 | struct dp_train_func *func; | 82 | struct dp_train_func *func; |
212 | struct dcb_entry *dcb; | 83 | struct dcb_entry *dcb; |
213 | int auxch; | ||
214 | int crtc; | 84 | int crtc; |
215 | u8 *dpcd; | 85 | u8 *dpcd; |
216 | int link_nr; | 86 | int link_nr; |
@@ -236,7 +106,7 @@ dp_set_link_config(struct drm_device *dev, struct dp_state *dp) | |||
236 | if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) | 106 | if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) |
237 | sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; | 107 | sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; |
238 | 108 | ||
239 | auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2); | 109 | auxch_wr(dev, dp->auxch, DP_LINK_BW_SET, sink, 2); |
240 | } | 110 | } |
241 | 111 | ||
242 | static void | 112 | static void |
@@ -248,10 +118,10 @@ dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 pattern) | |||
248 | 118 | ||
249 | dp->func->train_set(dev, dp->dcb, pattern); | 119 | dp->func->train_set(dev, dp->dcb, pattern); |
250 | 120 | ||
251 | auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1); | 121 | auxch_rd(dev, dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1); |
252 | sink_tp &= ~DP_TRAINING_PATTERN_MASK; | 122 | sink_tp &= ~DP_TRAINING_PATTERN_MASK; |
253 | sink_tp |= pattern; | 123 | sink_tp |= pattern; |
254 | auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1); | 124 | auxch_wr(dev, dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1); |
255 | } | 125 | } |
256 | 126 | ||
257 | static int | 127 | static int |
@@ -274,7 +144,7 @@ dp_link_train_commit(struct drm_device *dev, struct dp_state *dp) | |||
274 | dp->func->train_adj(dev, dp->dcb, i, lvsw, lpre); | 144 | dp->func->train_adj(dev, dp->dcb, i, lvsw, lpre); |
275 | } | 145 | } |
276 | 146 | ||
277 | return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4); | 147 | return auxch_wr(dev, dp->auxch, DP_TRAINING_LANE0_SET, dp->conf, 4); |
278 | } | 148 | } |
279 | 149 | ||
280 | static int | 150 | static int |
@@ -284,7 +154,7 @@ dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay) | |||
284 | 154 | ||
285 | udelay(delay); | 155 | udelay(delay); |
286 | 156 | ||
287 | ret = auxch_tx(dev, dp->auxch, 9, DP_LANE0_1_STATUS, dp->stat, 6); | 157 | ret = auxch_rd(dev, dp->auxch, DP_LANE0_1_STATUS, dp->stat, 6); |
288 | if (ret) | 158 | if (ret) |
289 | return ret; | 159 | return ret; |
290 | 160 | ||
@@ -417,19 +287,17 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate, | |||
417 | struct nouveau_connector *nv_connector = | 287 | struct nouveau_connector *nv_connector = |
418 | nouveau_encoder_connector_get(nv_encoder); | 288 | nouveau_encoder_connector_get(nv_encoder); |
419 | struct drm_device *dev = encoder->dev; | 289 | struct drm_device *dev = encoder->dev; |
420 | struct nouveau_i2c_chan *auxch; | ||
421 | const u32 bw_list[] = { 270000, 162000, 0 }; | 290 | const u32 bw_list[] = { 270000, 162000, 0 }; |
422 | const u32 *link_bw = bw_list; | 291 | const u32 *link_bw = bw_list; |
423 | struct dp_state dp; | 292 | struct dp_state dp; |
424 | 293 | ||
425 | auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); | 294 | dp.auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); |
426 | if (!auxch) | 295 | if (!dp.auxch) |
427 | return false; | 296 | return false; |
428 | 297 | ||
429 | dp.func = func; | 298 | dp.func = func; |
430 | dp.dcb = nv_encoder->dcb; | 299 | dp.dcb = nv_encoder->dcb; |
431 | dp.crtc = nv_crtc->index; | 300 | dp.crtc = nv_crtc->index; |
432 | dp.auxch = auxch->drive; | ||
433 | dp.dpcd = nv_encoder->dp.dpcd; | 301 | dp.dpcd = nv_encoder->dp.dpcd; |
434 | 302 | ||
435 | /* adjust required bandwidth for 8B/10B coding overhead */ | 303 | /* adjust required bandwidth for 8B/10B coding overhead */ |
@@ -491,7 +359,7 @@ nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate, | |||
491 | struct dp_train_func *func) | 359 | struct dp_train_func *func) |
492 | { | 360 | { |
493 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | 361 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
494 | struct nouveau_i2c_chan *auxch; | 362 | struct nouveau_i2c_port *auxch; |
495 | u8 status; | 363 | u8 status; |
496 | 364 | ||
497 | auxch = nouveau_i2c_find(encoder->dev, nv_encoder->dcb->i2c_index); | 365 | auxch = nouveau_i2c_find(encoder->dev, nv_encoder->dcb->i2c_index); |
@@ -503,14 +371,14 @@ nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate, | |||
503 | else | 371 | else |
504 | status = DP_SET_POWER_D3; | 372 | status = DP_SET_POWER_D3; |
505 | 373 | ||
506 | nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); | 374 | auxch_wr(encoder->dev, auxch, DP_SET_POWER, &status, 1); |
507 | 375 | ||
508 | if (mode == DRM_MODE_DPMS_ON) | 376 | if (mode == DRM_MODE_DPMS_ON) |
509 | nouveau_dp_link_train(encoder, datarate, func); | 377 | nouveau_dp_link_train(encoder, datarate, func); |
510 | } | 378 | } |
511 | 379 | ||
512 | static void | 380 | static void |
513 | nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_chan *auxch, | 381 | nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch, |
514 | u8 *dpcd) | 382 | u8 *dpcd) |
515 | { | 383 | { |
516 | u8 buf[3]; | 384 | u8 buf[3]; |
@@ -518,11 +386,11 @@ nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_chan *auxch, | |||
518 | if (!(dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) | 386 | if (!(dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) |
519 | return; | 387 | return; |
520 | 388 | ||
521 | if (!auxch_tx(dev, auxch->drive, 9, DP_SINK_OUI, buf, 3)) | 389 | if (!auxch_rd(dev, auxch, DP_SINK_OUI, buf, 3)) |
522 | NV_DEBUG_KMS(dev, "Sink OUI: %02hx%02hx%02hx\n", | 390 | NV_DEBUG_KMS(dev, "Sink OUI: %02hx%02hx%02hx\n", |
523 | buf[0], buf[1], buf[2]); | 391 | buf[0], buf[1], buf[2]); |
524 | 392 | ||
525 | if (!auxch_tx(dev, auxch->drive, 9, DP_BRANCH_OUI, buf, 3)) | 393 | if (!auxch_rd(dev, auxch, DP_BRANCH_OUI, buf, 3)) |
526 | NV_DEBUG_KMS(dev, "Branch OUI: %02hx%02hx%02hx\n", | 394 | NV_DEBUG_KMS(dev, "Branch OUI: %02hx%02hx%02hx\n", |
527 | buf[0], buf[1], buf[2]); | 395 | buf[0], buf[1], buf[2]); |
528 | 396 | ||
@@ -533,7 +401,7 @@ nouveau_dp_detect(struct drm_encoder *encoder) | |||
533 | { | 401 | { |
534 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | 402 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
535 | struct drm_device *dev = encoder->dev; | 403 | struct drm_device *dev = encoder->dev; |
536 | struct nouveau_i2c_chan *auxch; | 404 | struct nouveau_i2c_port *auxch; |
537 | u8 *dpcd = nv_encoder->dp.dpcd; | 405 | u8 *dpcd = nv_encoder->dp.dpcd; |
538 | int ret; | 406 | int ret; |
539 | 407 | ||
@@ -541,7 +409,7 @@ nouveau_dp_detect(struct drm_encoder *encoder) | |||
541 | if (!auxch) | 409 | if (!auxch) |
542 | return false; | 410 | return false; |
543 | 411 | ||
544 | ret = auxch_tx(dev, auxch->drive, 9, DP_DPCD_REV, dpcd, 8); | 412 | ret = auxch_rd(dev, auxch, DP_DPCD_REV, dpcd, 8); |
545 | if (ret) | 413 | if (ret) |
546 | return false; | 414 | return false; |
547 | 415 | ||
@@ -566,58 +434,3 @@ nouveau_dp_detect(struct drm_encoder *encoder) | |||
566 | 434 | ||
567 | return true; | 435 | return true; |
568 | } | 436 | } |
569 | |||
570 | int | ||
571 | nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, | ||
572 | uint8_t *data, int data_nr) | ||
573 | { | ||
574 | return auxch_tx(auxch->dev, auxch->drive, cmd, addr, data, data_nr); | ||
575 | } | ||
576 | |||
577 | static int | ||
578 | nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | ||
579 | { | ||
580 | struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap; | ||
581 | struct i2c_msg *msg = msgs; | ||
582 | int ret, mcnt = num; | ||
583 | |||
584 | while (mcnt--) { | ||
585 | u8 remaining = msg->len; | ||
586 | u8 *ptr = msg->buf; | ||
587 | |||
588 | while (remaining) { | ||
589 | u8 cnt = (remaining > 16) ? 16 : remaining; | ||
590 | u8 cmd; | ||
591 | |||
592 | if (msg->flags & I2C_M_RD) | ||
593 | cmd = AUX_I2C_READ; | ||
594 | else | ||
595 | cmd = AUX_I2C_WRITE; | ||
596 | |||
597 | if (mcnt || remaining > 16) | ||
598 | cmd |= AUX_I2C_MOT; | ||
599 | |||
600 | ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt); | ||
601 | if (ret < 0) | ||
602 | return ret; | ||
603 | |||
604 | ptr += cnt; | ||
605 | remaining -= cnt; | ||
606 | } | ||
607 | |||
608 | msg++; | ||
609 | } | ||
610 | |||
611 | return num; | ||
612 | } | ||
613 | |||
614 | static u32 | ||
615 | nouveau_dp_i2c_func(struct i2c_adapter *adap) | ||
616 | { | ||
617 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
618 | } | ||
619 | |||
620 | const struct i2c_algorithm nouveau_dp_i2c_algo = { | ||
621 | .master_xfer = nouveau_dp_i2c_xfer, | ||
622 | .functionality = nouveau_dp_i2c_func | ||
623 | }; | ||