diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2010-07-29 07:01:45 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-08-05 18:33:40 -0400 |
commit | c020c9a8ca569cec19a147c9cd44fe6c3c9cdcee (patch) | |
tree | ec881555d14a355bb480750b99f3711bada264a2 | |
parent | 96576a9e1a0cdb8a43d3af5846be0948f52b4460 (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.c | 87 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_i2c.c | 39 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_i2c.h | 8 |
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 | ||
575 | int | 575 | static int |
576 | nouveau_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, | 576 | nouveau_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 | |||
626 | static u32 | ||
627 | nouveau_dp_i2c_func(struct i2c_adapter *adap) | ||
628 | { | ||
629 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
617 | } | 630 | } |
618 | 631 | ||
632 | const 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; | |||
33 | struct nouveau_i2c_chan { | 33 | struct 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); | |||
49 | int nouveau_i2c_identify(struct drm_device *dev, const char *what, | 46 | int 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 | ||
52 | int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte, | 49 | extern 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__ */ |