aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-05-18 21:54:09 -0400
committerBen Skeggs <bskeggs@redhat.com>2014-06-11 02:10:43 -0400
commitbb7ef1ec2e383d80acb9b0523a4692857b34ef1d (patch)
tree5f77b2b70cd6aac84239589a1bcea5bc2b8dfc7e /drivers/gpu/drm/nouveau
parentb8407c9e504f43a50ba0de746c5e8958521165aa (diff)
drm/nouveau/disp/dp: maintain receiver caps in response to hpd signal
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c72
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h4
2 files changed, 68 insertions, 8 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
index ea6483d066c1..7f5588755436 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
@@ -26,21 +26,73 @@
26 26
27#include "outpdp.h" 27#include "outpdp.h"
28#include "conn.h" 28#include "conn.h"
29#include "dport.h"
29 30
30static int 31static void
31nvkm_output_dp_service(void *data, u32 type, int index) 32nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present)
32{ 33{
33 struct nvkm_output_dp *outp = data; 34 struct nouveau_i2c_port *port = outp->base.edid;
34 DBG("IRQ: %d\n", type); 35 if (present) {
35 return NVKM_EVENT_KEEP; 36 if (!outp->present) {
37 nouveau_i2c(port)->acquire_pad(port, 0);
38 DBG("aux power -> always\n");
39 outp->present = true;
40 }
41 } else {
42 if (outp->present) {
43 nouveau_i2c(port)->release_pad(port);
44 DBG("aux power -> demand\n");
45 outp->present = false;
46 }
47 }
48}
49
50static void
51nvkm_output_dp_detect(struct nvkm_output_dp *outp)
52{
53 struct nouveau_i2c_port *port = outp->base.edid;
54 int ret = nouveau_i2c(port)->acquire_pad(port, 0);
55 if (ret == 0) {
56 ret = nv_rdaux(outp->base.edid, DPCD_RC00_DPCD_REV,
57 outp->dpcd, sizeof(outp->dpcd));
58 nvkm_output_dp_enable(outp, ret == 0);
59 nouveau_i2c(port)->release_pad(port);
60 }
61}
62
63static void
64nvkm_output_dp_service_work(struct work_struct *work)
65{
66 struct nvkm_output_dp *outp = container_of(work, typeof(*outp), work);
67 struct nouveau_disp *disp = nouveau_disp(outp);
68 int type = atomic_xchg(&outp->pending, 0);
69 u32 send = 0;
70
71 if (type & (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG)) {
72 nvkm_output_dp_detect(outp);
73 if (type & NVKM_I2C_UNPLUG)
74 send |= NVKM_HPD_UNPLUG;
75 if (type & NVKM_I2C_PLUG)
76 send |= NVKM_HPD_PLUG;
77 nouveau_event_get(outp->base.conn->hpd.event);
78 }
79
80 if (type & NVKM_I2C_IRQ) {
81 nouveau_event_get(outp->irq);
82 send |= NVKM_HPD_IRQ;
83 }
84
85 nouveau_event_trigger(disp->hpd, send, outp->base.info.connector);
36} 86}
37 87
38static int 88static int
39nvkm_output_dp_hotplug(void *data, u32 type, int index) 89nvkm_output_dp_service(void *data, u32 type, int index)
40{ 90{
41 struct nvkm_output_dp *outp = data; 91 struct nvkm_output_dp *outp = data;
42 DBG("HPD: %d\n", type); 92 DBG("HPD: %d\n", type);
43 return NVKM_EVENT_KEEP; 93 atomic_or(type, &outp->pending);
94 schedule_work(&outp->work);
95 return NVKM_EVENT_DROP;
44} 96}
45 97
46int 98int
@@ -48,6 +100,7 @@ _nvkm_output_dp_fini(struct nouveau_object *object, bool suspend)
48{ 100{
49 struct nvkm_output_dp *outp = (void *)object; 101 struct nvkm_output_dp *outp = (void *)object;
50 nouveau_event_put(outp->irq); 102 nouveau_event_put(outp->irq);
103 nvkm_output_dp_enable(outp, false);
51 return nvkm_output_fini(&outp->base, suspend); 104 return nvkm_output_fini(&outp->base, suspend);
52} 105}
53 106
@@ -55,6 +108,7 @@ int
55_nvkm_output_dp_init(struct nouveau_object *object) 108_nvkm_output_dp_init(struct nouveau_object *object)
56{ 109{
57 struct nvkm_output_dp *outp = (void *)object; 110 struct nvkm_output_dp *outp = (void *)object;
111 nvkm_output_dp_detect(outp);
58 return nvkm_output_init(&outp->base); 112 return nvkm_output_init(&outp->base);
59} 113}
60 114
@@ -113,10 +167,12 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
113 return ret; 167 return ret;
114 } 168 }
115 169
170 INIT_WORK(&outp->work, nvkm_output_dp_service_work);
171
116 /* hotplug detect, replaces gpio-based mechanism with aux events */ 172 /* hotplug detect, replaces gpio-based mechanism with aux events */
117 ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, 173 ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
118 outp->base.edid->index, 174 outp->base.edid->index,
119 nvkm_output_dp_hotplug, outp, 175 nvkm_output_dp_service, outp,
120 &outp->base.conn->hpd.event); 176 &outp->base.conn->hpd.event);
121 if (ret) { 177 if (ret) {
122 ERR("error monitoring aux hpd events: %d\n", ret); 178 ERR("error monitoring aux hpd events: %d\n", ret);
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h
index 22f692da1b1d..228b5d845640 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h
@@ -14,6 +14,10 @@ struct nvkm_output_dp {
14 14
15 struct nouveau_eventh *irq; 15 struct nouveau_eventh *irq;
16 struct nouveau_eventh *hpd; 16 struct nouveau_eventh *hpd;
17 struct work_struct work;
18 atomic_t pending;
19 bool present;
20 u8 dpcd[16];
17}; 21};
18 22
19#define nvkm_output_dp_create(p,e,c,b,i,d) \ 23#define nvkm_output_dp_create(p,e,c,b,i,d) \