diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-05-18 21:54:09 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-06-11 02:10:43 -0400 |
commit | bb7ef1ec2e383d80acb9b0523a4692857b34ef1d (patch) | |
tree | 5f77b2b70cd6aac84239589a1bcea5bc2b8dfc7e /drivers/gpu/drm/nouveau | |
parent | b8407c9e504f43a50ba0de746c5e8958521165aa (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.c | 72 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h | 4 |
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 | ||
30 | static int | 31 | static void |
31 | nvkm_output_dp_service(void *data, u32 type, int index) | 32 | nvkm_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 | |||
50 | static void | ||
51 | nvkm_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 | |||
63 | static void | ||
64 | nvkm_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 | ||
38 | static int | 88 | static int |
39 | nvkm_output_dp_hotplug(void *data, u32 type, int index) | 89 | nvkm_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 | ||
46 | int | 98 | int |
@@ -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) \ |