aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2010-07-29 07:01:45 -0400
committerBen Skeggs <bskeggs@redhat.com>2010-08-05 18:33:40 -0400
commitc020c9a8ca569cec19a147c9cd44fe6c3c9cdcee (patch)
treeec881555d14a355bb480750b99f3711bada264a2
parent96576a9e1a0cdb8a43d3af5846be0948f52b4460 (diff)
drm/nv50: use custom i2c algo for dp auxch
This makes it easier to see how this is working, and lets us transfer the EDID in blocks of 16 bytes. The primary reason for this change is because debug logs are rather hard to read with the hundreds of single-byte auxch transactions that occur. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c87
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.c39
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.h8
3 files changed, 72 insertions, 62 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 33742b11188b..8a1b188b4cd1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -572,47 +572,64 @@ out:
572 return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY); 572 return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY);
573} 573}
574 574
575int 575static int
576nouveau_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, 576nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
577 uint8_t write_byte, uint8_t *read_byte)
578{ 577{
579 struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; 578 struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap;
580 struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adapter;
581 struct drm_device *dev = auxch->dev; 579 struct drm_device *dev = auxch->dev;
582 int ret = 0, cmd, addr = algo_data->address; 580 struct i2c_msg *msg = msgs;
583 uint8_t *buf; 581 int ret, mcnt = num;
584
585 if (mode == MODE_I2C_READ) {
586 cmd = AUX_I2C_READ;
587 buf = read_byte;
588 } else {
589 cmd = (mode & MODE_I2C_READ) ? AUX_I2C_READ : AUX_I2C_WRITE;
590 buf = &write_byte;
591 }
592 582
593 if (!(mode & MODE_I2C_STOP)) 583 while (mcnt--) {
594 cmd |= AUX_I2C_MOT; 584 u8 remaining = msg->len;
585 u8 *ptr = msg->buf;
595 586
596 if (mode & MODE_I2C_START) 587 while (remaining) {
597 return 1; 588 u8 cnt = (remaining > 16) ? 16 : remaining;
589 u8 cmd;
598 590
599 for (;;) { 591 if (msg->flags & I2C_M_RD)
600 ret = nouveau_dp_auxch(auxch, cmd, addr, buf, 1); 592 cmd = AUX_I2C_READ;
601 if (ret < 0) 593 else
602 return ret; 594 cmd = AUX_I2C_WRITE;
603 595
604 switch (ret & NV50_AUXCH_STAT_REPLY_I2C) { 596 if (mcnt || remaining > 16)
605 case NV50_AUXCH_STAT_REPLY_I2C_ACK: 597 cmd |= AUX_I2C_MOT;
606 return 1; 598
607 case NV50_AUXCH_STAT_REPLY_I2C_NACK: 599 ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt);
608 return -EREMOTEIO; 600 if (ret < 0)
609 case NV50_AUXCH_STAT_REPLY_I2C_DEFER: 601 return ret;
610 udelay(100); 602
611 break; 603 switch (ret & NV50_AUXCH_STAT_REPLY_I2C) {
612 default: 604 case NV50_AUXCH_STAT_REPLY_I2C_ACK:
613 NV_ERROR(dev, "invalid auxch status: 0x%08x\n", ret); 605 break;
614 return -EREMOTEIO; 606 case NV50_AUXCH_STAT_REPLY_I2C_NACK:
607 return -EREMOTEIO;
608 case NV50_AUXCH_STAT_REPLY_I2C_DEFER:
609 udelay(100);
610 continue;
611 default:
612 NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret);
613 return -EREMOTEIO;
614 }
615
616 ptr += cnt;
617 remaining -= cnt;
615 } 618 }
619
620 msg++;
616 } 621 }
622
623 return num;
624}
625
626static u32
627nouveau_dp_i2c_func(struct i2c_adapter *adap)
628{
629 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
617} 630}
618 631
632const struct i2c_algorithm nouveau_dp_i2c_algo = {
633 .master_xfer = nouveau_dp_i2c_xfer,
634 .functionality = nouveau_dp_i2c_func
635};
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index cb0cb34440c6..9df711fdbbc5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -174,26 +174,26 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
174 174
175 switch (entry->port_type) { 175 switch (entry->port_type) {
176 case 0: 176 case 0:
177 i2c->algo.bit.setsda = nv04_i2c_setsda; 177 i2c->bit.setsda = nv04_i2c_setsda;
178 i2c->algo.bit.setscl = nv04_i2c_setscl; 178 i2c->bit.setscl = nv04_i2c_setscl;
179 i2c->algo.bit.getsda = nv04_i2c_getsda; 179 i2c->bit.getsda = nv04_i2c_getsda;
180 i2c->algo.bit.getscl = nv04_i2c_getscl; 180 i2c->bit.getscl = nv04_i2c_getscl;
181 i2c->rd = entry->read; 181 i2c->rd = entry->read;
182 i2c->wr = entry->write; 182 i2c->wr = entry->write;
183 break; 183 break;
184 case 4: 184 case 4:
185 i2c->algo.bit.setsda = nv4e_i2c_setsda; 185 i2c->bit.setsda = nv4e_i2c_setsda;
186 i2c->algo.bit.setscl = nv4e_i2c_setscl; 186 i2c->bit.setscl = nv4e_i2c_setscl;
187 i2c->algo.bit.getsda = nv4e_i2c_getsda; 187 i2c->bit.getsda = nv4e_i2c_getsda;
188 i2c->algo.bit.getscl = nv4e_i2c_getscl; 188 i2c->bit.getscl = nv4e_i2c_getscl;
189 i2c->rd = 0x600800 + entry->read; 189 i2c->rd = 0x600800 + entry->read;
190 i2c->wr = 0x600800 + entry->write; 190 i2c->wr = 0x600800 + entry->write;
191 break; 191 break;
192 case 5: 192 case 5:
193 i2c->algo.bit.setsda = nv50_i2c_setsda; 193 i2c->bit.setsda = nv50_i2c_setsda;
194 i2c->algo.bit.setscl = nv50_i2c_setscl; 194 i2c->bit.setscl = nv50_i2c_setscl;
195 i2c->algo.bit.getsda = nv50_i2c_getsda; 195 i2c->bit.getsda = nv50_i2c_getsda;
196 i2c->algo.bit.getscl = nv50_i2c_getscl; 196 i2c->bit.getscl = nv50_i2c_getscl;
197 i2c->rd = nv50_i2c_port[entry->read]; 197 i2c->rd = nv50_i2c_port[entry->read];
198 i2c->wr = i2c->rd; 198 i2c->wr = i2c->rd;
199 break; 199 break;
@@ -216,17 +216,14 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
216 i2c_set_adapdata(&i2c->adapter, i2c); 216 i2c_set_adapdata(&i2c->adapter, i2c);
217 217
218 if (entry->port_type < 6) { 218 if (entry->port_type < 6) {
219 i2c->adapter.algo_data = &i2c->algo.bit; 219 i2c->adapter.algo_data = &i2c->bit;
220 i2c->algo.bit.udelay = 40; 220 i2c->bit.udelay = 40;
221 i2c->algo.bit.timeout = usecs_to_jiffies(5000); 221 i2c->bit.timeout = usecs_to_jiffies(5000);
222 i2c->algo.bit.data = i2c; 222 i2c->bit.data = i2c;
223 ret = i2c_bit_add_bus(&i2c->adapter); 223 ret = i2c_bit_add_bus(&i2c->adapter);
224 } else { 224 } else {
225 i2c->adapter.algo_data = &i2c->algo.dp; 225 i2c->adapter.algo = &nouveau_dp_i2c_algo;
226 i2c->algo.dp.running = false; 226 ret = i2c_add_adapter(&i2c->adapter);
227 i2c->algo.dp.address = 0;
228 i2c->algo.dp.aux_ch = nouveau_dp_i2c_aux_ch;
229 ret = i2c_dp_aux_add_bus(&i2c->adapter);
230 } 227 }
231 228
232 if (ret) { 229 if (ret) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h
index 6dd2f8713cd1..f71cb32f7571 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.h
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h
@@ -33,10 +33,7 @@ struct dcb_i2c_entry;
33struct nouveau_i2c_chan { 33struct nouveau_i2c_chan {
34 struct i2c_adapter adapter; 34 struct i2c_adapter adapter;
35 struct drm_device *dev; 35 struct drm_device *dev;
36 union { 36 struct i2c_algo_bit_data bit;
37 struct i2c_algo_bit_data bit;
38 struct i2c_algo_dp_aux_data dp;
39 } algo;
40 unsigned rd; 37 unsigned rd;
41 unsigned wr; 38 unsigned wr;
42 unsigned data; 39 unsigned data;
@@ -49,7 +46,6 @@ bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
49int nouveau_i2c_identify(struct drm_device *dev, const char *what, 46int nouveau_i2c_identify(struct drm_device *dev, const char *what,
50 struct i2c_board_info *info, int index); 47 struct i2c_board_info *info, int index);
51 48
52int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte, 49extern const struct i2c_algorithm nouveau_dp_i2c_algo;
53 uint8_t *read_byte);
54 50
55#endif /* __NOUVEAU_I2C_H__ */ 51#endif /* __NOUVEAU_I2C_H__ */