diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-07-20 01:50:14 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-09-20 02:09:03 -0400 |
commit | 43720133888f3713b534aec520783498f1bf5db3 (patch) | |
tree | 8138721808f96271c8fc96ee200748405a2eb0a0 /drivers/gpu | |
parent | 91a8f1ea4bd98a7de888f7d56e28b72cc0c63ca1 (diff) |
drm/nouveau/dp: rewrite auxch transaction routines
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_dp.c | 236 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 1 |
2 files changed, 132 insertions, 105 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 44de23d9a437..f8ebd09ee3a6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c | |||
@@ -29,6 +29,136 @@ | |||
29 | #include "nouveau_connector.h" | 29 | #include "nouveau_connector.h" |
30 | #include "nouveau_encoder.h" | 30 | #include "nouveau_encoder.h" |
31 | 31 | ||
32 | /****************************************************************************** | ||
33 | * aux channel util functions | ||
34 | *****************************************************************************/ | ||
35 | #define AUX_DBG(fmt, args...) do { \ | ||
36 | if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_AUXCH) { \ | ||
37 | NV_PRINTK(KERN_DEBUG, dev, "AUXCH(%d): " fmt, ch, ##args); \ | ||
38 | } \ | ||
39 | } while (0) | ||
40 | #define AUX_ERR(fmt, args...) NV_ERROR(dev, "AUXCH(%d): " fmt, ch, ##args) | ||
41 | |||
42 | static void | ||
43 | auxch_fini(struct drm_device *dev, int ch) | ||
44 | { | ||
45 | nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); | ||
46 | } | ||
47 | |||
48 | static int | ||
49 | auxch_init(struct drm_device *dev, int ch) | ||
50 | { | ||
51 | const u32 unksel = 1; /* nfi which to use, or if it matters.. */ | ||
52 | const u32 ureq = unksel ? 0x00100000 : 0x00200000; | ||
53 | const u32 urep = unksel ? 0x01000000 : 0x02000000; | ||
54 | u32 ctrl, timeout; | ||
55 | |||
56 | /* wait up to 1ms for any previous transaction to be done... */ | ||
57 | timeout = 1000; | ||
58 | do { | ||
59 | ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); | ||
60 | udelay(1); | ||
61 | if (!timeout--) { | ||
62 | AUX_ERR("begin idle timeout 0x%08x", ctrl); | ||
63 | return -EBUSY; | ||
64 | } | ||
65 | } while (ctrl & 0x03010000); | ||
66 | |||
67 | /* set some magic, and wait up to 1ms for it to appear */ | ||
68 | nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); | ||
69 | timeout = 1000; | ||
70 | do { | ||
71 | ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); | ||
72 | udelay(1); | ||
73 | if (!timeout--) { | ||
74 | AUX_ERR("magic wait 0x%08x\n", ctrl); | ||
75 | auxch_fini(dev, ch); | ||
76 | return -EBUSY; | ||
77 | } | ||
78 | } while ((ctrl & 0x03000000) != urep); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int | ||
84 | auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size) | ||
85 | { | ||
86 | u32 ctrl, stat, timeout, retries; | ||
87 | u32 xbuf[4] = {}; | ||
88 | int ret, i; | ||
89 | |||
90 | AUX_DBG("%d: 0x%08x %d\n", type, addr, size); | ||
91 | |||
92 | ret = auxch_init(dev, ch); | ||
93 | if (ret) | ||
94 | goto out; | ||
95 | |||
96 | stat = nv_rd32(dev, 0x00e4e8 + (ch * 0x50)); | ||
97 | if (!(stat & 0x10000000)) { | ||
98 | AUX_DBG("sink not detected\n"); | ||
99 | ret = -ENXIO; | ||
100 | goto out; | ||
101 | } | ||
102 | |||
103 | if (!(type & 1)) { | ||
104 | memcpy(xbuf, data, size); | ||
105 | for (i = 0; i < 16; i += 4) { | ||
106 | AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); | ||
107 | nv_wr32(dev, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); | ||
112 | ctrl &= ~0x0001f0ff; | ||
113 | ctrl |= type << 12; | ||
114 | ctrl |= size - 1; | ||
115 | nv_wr32(dev, 0x00e4e0 + (ch * 0x50), addr); | ||
116 | |||
117 | /* retry transaction a number of times on failure... */ | ||
118 | ret = -EREMOTEIO; | ||
119 | for (retries = 0; retries < 32; retries++) { | ||
120 | /* reset, and delay a while if this is a retry */ | ||
121 | nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); | ||
122 | nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); | ||
123 | if (retries) | ||
124 | udelay(400); | ||
125 | |||
126 | /* transaction request, wait up to 1ms for it to complete */ | ||
127 | nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); | ||
128 | |||
129 | timeout = 1000; | ||
130 | do { | ||
131 | ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); | ||
132 | udelay(1); | ||
133 | if (!timeout--) { | ||
134 | AUX_ERR("tx req timeout 0x%08x\n", ctrl); | ||
135 | goto out; | ||
136 | } | ||
137 | } while (ctrl & 0x00010000); | ||
138 | |||
139 | /* read status, and check if transaction completed ok */ | ||
140 | stat = nv_mask(dev, 0x00e4e8 + (ch * 0x50), 0, 0); | ||
141 | if (!(stat & 0x000f0f00)) { | ||
142 | ret = 0; | ||
143 | break; | ||
144 | } | ||
145 | |||
146 | AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); | ||
147 | } | ||
148 | |||
149 | if (type & 1) { | ||
150 | for (i = 0; i < 16; i += 4) { | ||
151 | xbuf[i / 4] = nv_rd32(dev, 0x00e4d0 + (ch * 0x50) + i); | ||
152 | AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); | ||
153 | } | ||
154 | memcpy(data, xbuf, size); | ||
155 | } | ||
156 | |||
157 | out: | ||
158 | auxch_fini(dev, ch); | ||
159 | return ret; | ||
160 | } | ||
161 | |||
32 | static int | 162 | static int |
33 | auxch_rd(struct drm_encoder *encoder, int address, uint8_t *buf, int size) | 163 | auxch_rd(struct drm_encoder *encoder, int address, uint8_t *buf, int size) |
34 | { | 164 | { |
@@ -480,98 +610,7 @@ int | |||
480 | nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, | 610 | nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, |
481 | uint8_t *data, int data_nr) | 611 | uint8_t *data, int data_nr) |
482 | { | 612 | { |
483 | struct drm_device *dev = auxch->dev; | 613 | return auxch_tx(auxch->dev, auxch->rd, cmd, addr, data, data_nr); |
484 | uint32_t tmp, ctrl, stat = 0, data32[4] = {}; | ||
485 | int ret = 0, i, index = auxch->rd; | ||
486 | |||
487 | NV_DEBUG_KMS(dev, "ch %d cmd %d addr 0x%x len %d\n", index, cmd, addr, data_nr); | ||
488 | |||
489 | tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); | ||
490 | nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp | 0x00100000); | ||
491 | tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); | ||
492 | if (!(tmp & 0x01000000)) { | ||
493 | NV_ERROR(dev, "expected bit 24 == 1, got 0x%08x\n", tmp); | ||
494 | ret = -EIO; | ||
495 | goto out; | ||
496 | } | ||
497 | |||
498 | for (i = 0; i < 3; i++) { | ||
499 | tmp = nv_rd32(dev, NV50_AUXCH_STAT(auxch->rd)); | ||
500 | if (tmp & NV50_AUXCH_STAT_STATE_READY) | ||
501 | break; | ||
502 | udelay(100); | ||
503 | } | ||
504 | |||
505 | if (i == 3) { | ||
506 | ret = -EBUSY; | ||
507 | goto out; | ||
508 | } | ||
509 | |||
510 | if (!(cmd & 1)) { | ||
511 | memcpy(data32, data, data_nr); | ||
512 | for (i = 0; i < 4; i++) { | ||
513 | NV_DEBUG_KMS(dev, "wr %d: 0x%08x\n", i, data32[i]); | ||
514 | nv_wr32(dev, NV50_AUXCH_DATA_OUT(index, i), data32[i]); | ||
515 | } | ||
516 | } | ||
517 | |||
518 | nv_wr32(dev, NV50_AUXCH_ADDR(index), addr); | ||
519 | ctrl = nv_rd32(dev, NV50_AUXCH_CTRL(index)); | ||
520 | ctrl &= ~(NV50_AUXCH_CTRL_CMD | NV50_AUXCH_CTRL_LEN); | ||
521 | ctrl |= (cmd << NV50_AUXCH_CTRL_CMD_SHIFT); | ||
522 | ctrl |= ((data_nr - 1) << NV50_AUXCH_CTRL_LEN_SHIFT); | ||
523 | |||
524 | for (i = 0; i < 16; i++) { | ||
525 | nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000); | ||
526 | nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl); | ||
527 | nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000); | ||
528 | if (!nv_wait(dev, NV50_AUXCH_CTRL(index), | ||
529 | 0x00010000, 0x00000000)) { | ||
530 | NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n", | ||
531 | nv_rd32(dev, NV50_AUXCH_CTRL(index))); | ||
532 | ret = -EBUSY; | ||
533 | goto out; | ||
534 | } | ||
535 | |||
536 | udelay(400); | ||
537 | |||
538 | stat = nv_rd32(dev, NV50_AUXCH_STAT(index)); | ||
539 | if ((stat & NV50_AUXCH_STAT_REPLY_AUX) != | ||
540 | NV50_AUXCH_STAT_REPLY_AUX_DEFER) | ||
541 | break; | ||
542 | } | ||
543 | |||
544 | if (i == 16) { | ||
545 | NV_ERROR(dev, "auxch DEFER too many times, bailing\n"); | ||
546 | ret = -EREMOTEIO; | ||
547 | goto out; | ||
548 | } | ||
549 | |||
550 | if (cmd & 1) { | ||
551 | if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) { | ||
552 | ret = -EREMOTEIO; | ||
553 | goto out; | ||
554 | } | ||
555 | |||
556 | for (i = 0; i < 4; i++) { | ||
557 | data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i)); | ||
558 | NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]); | ||
559 | } | ||
560 | memcpy(data, data32, data_nr); | ||
561 | } | ||
562 | |||
563 | out: | ||
564 | tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); | ||
565 | nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp & ~0x00100000); | ||
566 | tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); | ||
567 | if (tmp & 0x01000000) { | ||
568 | NV_ERROR(dev, "expected bit 24 == 0, got 0x%08x\n", tmp); | ||
569 | ret = -EIO; | ||
570 | } | ||
571 | |||
572 | udelay(400); | ||
573 | |||
574 | return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY); | ||
575 | } | 614 | } |
576 | 615 | ||
577 | static int | 616 | static int |
@@ -602,19 +641,6 @@ nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |||
602 | if (ret < 0) | 641 | if (ret < 0) |
603 | return ret; | 642 | return ret; |
604 | 643 | ||
605 | switch (ret & NV50_AUXCH_STAT_REPLY_I2C) { | ||
606 | case NV50_AUXCH_STAT_REPLY_I2C_ACK: | ||
607 | break; | ||
608 | case NV50_AUXCH_STAT_REPLY_I2C_NACK: | ||
609 | return -EREMOTEIO; | ||
610 | case NV50_AUXCH_STAT_REPLY_I2C_DEFER: | ||
611 | udelay(100); | ||
612 | continue; | ||
613 | default: | ||
614 | NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret); | ||
615 | return -EREMOTEIO; | ||
616 | } | ||
617 | |||
618 | ptr += cnt; | 644 | ptr += cnt; |
619 | remaining -= cnt; | 645 | remaining -= cnt; |
620 | } | 646 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 92c414af2074..bc035c4f42a8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -1570,6 +1570,7 @@ enum { | |||
1570 | NOUVEAU_REG_DEBUG_RMVIO = 0x80, | 1570 | NOUVEAU_REG_DEBUG_RMVIO = 0x80, |
1571 | NOUVEAU_REG_DEBUG_VGAATTR = 0x100, | 1571 | NOUVEAU_REG_DEBUG_VGAATTR = 0x100, |
1572 | NOUVEAU_REG_DEBUG_EVO = 0x200, | 1572 | NOUVEAU_REG_DEBUG_EVO = 0x200, |
1573 | NOUVEAU_REG_DEBUG_AUXCH = 0x400 | ||
1573 | }; | 1574 | }; |
1574 | 1575 | ||
1575 | #define NV_REG_DEBUG(type, dev, fmt, arg...) do { \ | 1576 | #define NV_REG_DEBUG(type, dev, fmt, arg...) do { \ |