aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-07-20 01:50:14 -0400
committerBen Skeggs <bskeggs@redhat.com>2011-09-20 02:09:03 -0400
commit43720133888f3713b534aec520783498f1bf5db3 (patch)
tree8138721808f96271c8fc96ee200748405a2eb0a0 /drivers/gpu
parent91a8f1ea4bd98a7de888f7d56e28b72cc0c63ca1 (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.c236
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h1
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
42static void
43auxch_fini(struct drm_device *dev, int ch)
44{
45 nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
46}
47
48static int
49auxch_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
83static int
84auxch_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
157out:
158 auxch_fini(dev, ch);
159 return ret;
160}
161
32static int 162static int
33auxch_rd(struct drm_encoder *encoder, int address, uint8_t *buf, int size) 163auxch_rd(struct drm_encoder *encoder, int address, uint8_t *buf, int size)
34{ 164{
@@ -480,98 +610,7 @@ int
480nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, 610nouveau_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
563out:
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
577static int 616static 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 { \