aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-02-02 21:56:16 -0500
committerBen Skeggs <bskeggs@redhat.com>2013-02-20 01:00:50 -0500
commit4f47643dbb4c345c5beebe53588682a7ff2c872a (patch)
tree824b98893e562bedab63d6987c1d248332b45f3f /drivers/gpu/drm/nouveau
parent0f0800661a125ddb038462570c869fe6f8ab5737 (diff)
drm/nouveau/gpio: use event interfaces for interrupt signalling
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/gpio.h31
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/base.c137
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c33
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c39
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c77
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c12
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c6
9 files changed, 127 insertions, 219 deletions
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
index 43cd20521a94..b0007b508567 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
@@ -3,6 +3,7 @@
3 3
4#include <core/subdev.h> 4#include <core/subdev.h>
5#include <core/device.h> 5#include <core/device.h>
6#include <core/event.h>
6 7
7#include <subdev/bios.h> 8#include <subdev/bios.h>
8#include <subdev/bios/gpio.h> 9#include <subdev/bios/gpio.h>
@@ -10,28 +11,18 @@
10struct nouveau_gpio { 11struct nouveau_gpio {
11 struct nouveau_subdev base; 12 struct nouveau_subdev base;
12 13
14 struct nouveau_event *events;
15
13 /* hardware interfaces */ 16 /* hardware interfaces */
14 void (*reset)(struct nouveau_gpio *, u8 func); 17 void (*reset)(struct nouveau_gpio *, u8 func);
15 int (*drive)(struct nouveau_gpio *, int line, int dir, int out); 18 int (*drive)(struct nouveau_gpio *, int line, int dir, int out);
16 int (*sense)(struct nouveau_gpio *, int line); 19 int (*sense)(struct nouveau_gpio *, int line);
17 void (*irq_enable)(struct nouveau_gpio *, int line, bool);
18 20
19 /* software interfaces */ 21 /* software interfaces */
20 int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line, 22 int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
21 struct dcb_gpio_func *); 23 struct dcb_gpio_func *);
22 int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state); 24 int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state);
23 int (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line); 25 int (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line);
24 int (*irq)(struct nouveau_gpio *, int idx, u8 tag, u8 line, bool on);
25
26 /* interrupt handling */
27 struct list_head isr;
28 spinlock_t lock;
29
30 void (*isr_run)(struct nouveau_gpio *, int idx, u32 mask);
31 int (*isr_add)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
32 void (*)(void *, int state), void *data);
33 void (*isr_del)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
34 void (*)(void *, int state), void *data);
35}; 26};
36 27
37static inline struct nouveau_gpio * 28static inline struct nouveau_gpio *
@@ -42,14 +33,17 @@ nouveau_gpio(void *obj)
42 33
43#define nouveau_gpio_create(p,e,o,l,d) \ 34#define nouveau_gpio_create(p,e,o,l,d) \
44 nouveau_gpio_create_((p), (e), (o), (l), sizeof(**d), (void **)d) 35 nouveau_gpio_create_((p), (e), (o), (l), sizeof(**d), (void **)d)
45#define nouveau_gpio_destroy(p) \ 36#define nouveau_gpio_destroy(p) ({ \
46 nouveau_subdev_destroy(&(p)->base) 37 struct nouveau_gpio *gpio = (p); \
38 _nouveau_gpio_dtor(nv_object(gpio)); \
39})
47#define nouveau_gpio_fini(p,s) \ 40#define nouveau_gpio_fini(p,s) \
48 nouveau_subdev_fini(&(p)->base, (s)) 41 nouveau_subdev_fini(&(p)->base, (s))
49 42
50int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, 43int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
51 struct nouveau_oclass *, int, int, void **); 44 struct nouveau_oclass *, int, int, void **);
52int nouveau_gpio_init(struct nouveau_gpio *); 45void _nouveau_gpio_dtor(struct nouveau_object *);
46int nouveau_gpio_init(struct nouveau_gpio *);
53 47
54extern struct nouveau_oclass nv10_gpio_oclass; 48extern struct nouveau_oclass nv10_gpio_oclass;
55extern struct nouveau_oclass nv50_gpio_oclass; 49extern struct nouveau_oclass nv50_gpio_oclass;
@@ -59,6 +53,7 @@ void nv50_gpio_dtor(struct nouveau_object *);
59int nv50_gpio_init(struct nouveau_object *); 53int nv50_gpio_init(struct nouveau_object *);
60int nv50_gpio_fini(struct nouveau_object *, bool); 54int nv50_gpio_fini(struct nouveau_object *, bool);
61void nv50_gpio_intr(struct nouveau_subdev *); 55void nv50_gpio_intr(struct nouveau_subdev *);
62void nv50_gpio_irq_enable(struct nouveau_gpio *, int line, bool); 56void nv50_gpio_intr_enable(struct nouveau_event *, int line);
57void nv50_gpio_intr_disable(struct nouveau_event *, int line);
63 58
64#endif 59#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
index 6f574fdc27c1..d422acc9af15 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
@@ -102,129 +102,12 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
102 return ret; 102 return ret;
103} 103}
104 104
105static int 105void
106nouveau_gpio_irq(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, bool on) 106_nouveau_gpio_dtor(struct nouveau_object *object)
107{
108 struct dcb_gpio_func func;
109 int ret;
110
111 ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
112 if (ret == 0) {
113 if (idx == 0 && gpio->irq_enable)
114 gpio->irq_enable(gpio, func.line, on);
115 else
116 ret = -ENODEV;
117 }
118
119 return ret;
120}
121
122struct gpio_isr {
123 struct nouveau_gpio *gpio;
124 struct list_head head;
125 struct work_struct work;
126 int idx;
127 struct dcb_gpio_func func;
128 void (*handler)(void *, int);
129 void *data;
130 bool inhibit;
131};
132
133static void
134nouveau_gpio_isr_bh(struct work_struct *work)
135{
136 struct gpio_isr *isr = container_of(work, struct gpio_isr, work);
137 struct nouveau_gpio *gpio = isr->gpio;
138 unsigned long flags;
139 int state;
140
141 state = nouveau_gpio_get(gpio, isr->idx, isr->func.func,
142 isr->func.line);
143 if (state >= 0)
144 isr->handler(isr->data, state);
145
146 spin_lock_irqsave(&gpio->lock, flags);
147 isr->inhibit = false;
148 spin_unlock_irqrestore(&gpio->lock, flags);
149}
150
151static void
152nouveau_gpio_isr_run(struct nouveau_gpio *gpio, int idx, u32 line_mask)
153{
154 struct gpio_isr *isr;
155
156 if (idx != 0)
157 return;
158
159 spin_lock(&gpio->lock);
160 list_for_each_entry(isr, &gpio->isr, head) {
161 if (line_mask & (1 << isr->func.line)) {
162 if (isr->inhibit)
163 continue;
164 isr->inhibit = true;
165 schedule_work(&isr->work);
166 }
167 }
168 spin_unlock(&gpio->lock);
169}
170
171static int
172nouveau_gpio_isr_add(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
173 void (*handler)(void *, int), void *data)
174{
175 struct gpio_isr *isr;
176 unsigned long flags;
177 int ret;
178
179 isr = kzalloc(sizeof(*isr), GFP_KERNEL);
180 if (!isr)
181 return -ENOMEM;
182
183 ret = nouveau_gpio_find(gpio, idx, tag, line, &isr->func);
184 if (ret) {
185 kfree(isr);
186 return ret;
187 }
188
189 INIT_WORK(&isr->work, nouveau_gpio_isr_bh);
190 isr->gpio = gpio;
191 isr->handler = handler;
192 isr->data = data;
193 isr->idx = idx;
194
195 spin_lock_irqsave(&gpio->lock, flags);
196 list_add(&isr->head, &gpio->isr);
197 spin_unlock_irqrestore(&gpio->lock, flags);
198 return 0;
199}
200
201static void
202nouveau_gpio_isr_del(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
203 void (*handler)(void *, int), void *data)
204{ 107{
205 struct gpio_isr *isr, *tmp; 108 struct nouveau_gpio *gpio = (void *)object;
206 struct dcb_gpio_func func; 109 nouveau_event_destroy(&gpio->events);
207 unsigned long flags; 110 nouveau_subdev_destroy(&gpio->base);
208 LIST_HEAD(tofree);
209 int ret;
210
211 ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
212 if (ret == 0) {
213 spin_lock_irqsave(&gpio->lock, flags);
214 list_for_each_entry_safe(isr, tmp, &gpio->isr, head) {
215 if (memcmp(&isr->func, &func, sizeof(func)) ||
216 isr->idx != idx ||
217 isr->handler != handler || isr->data != data)
218 continue;
219 list_move_tail(&isr->head, &tofree);
220 }
221 spin_unlock_irqrestore(&gpio->lock, flags);
222
223 list_for_each_entry_safe(isr, tmp, &tofree, head) {
224 flush_work(&isr->work);
225 kfree(isr);
226 }
227 }
228} 111}
229 112
230int 113int
@@ -242,15 +125,13 @@ nouveau_gpio_create_(struct nouveau_object *parent,
242 if (ret) 125 if (ret)
243 return ret; 126 return ret;
244 127
128 ret = nouveau_event_create(lines, &gpio->events);
129 if (ret)
130 return ret;
131
245 gpio->find = nouveau_gpio_find; 132 gpio->find = nouveau_gpio_find;
246 gpio->set = nouveau_gpio_set; 133 gpio->set = nouveau_gpio_set;
247 gpio->get = nouveau_gpio_get; 134 gpio->get = nouveau_gpio_get;
248 gpio->irq = nouveau_gpio_irq;
249 gpio->isr_run = nouveau_gpio_isr_run;
250 gpio->isr_add = nouveau_gpio_isr_add;
251 gpio->isr_del = nouveau_gpio_isr_del;
252 INIT_LIST_HEAD(&gpio->isr);
253 spin_lock_init(&gpio->lock);
254 return 0; 135 return 0;
255} 136}
256 137
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
index cf38d2a1d7f1..9665f5f70ee3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
@@ -83,27 +83,36 @@ nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
83} 83}
84 84
85static void 85static void
86nv10_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on)
87{
88 u32 mask = 0x00010001 << line;
89
90 nv_wr32(gpio, 0x001104, mask);
91 nv_mask(gpio, 0x001144, mask, on ? mask : 0);
92}
93
94static void
95nv10_gpio_intr(struct nouveau_subdev *subdev) 86nv10_gpio_intr(struct nouveau_subdev *subdev)
96{ 87{
97 struct nv10_gpio_priv *priv = (void *)subdev; 88 struct nv10_gpio_priv *priv = (void *)subdev;
98 u32 intr = nv_rd32(priv, 0x001104); 89 u32 intr = nv_rd32(priv, 0x001104);
99 u32 hi = (intr & 0x0000ffff) >> 0; 90 u32 hi = (intr & 0x0000ffff) >> 0;
100 u32 lo = (intr & 0xffff0000) >> 16; 91 u32 lo = (intr & 0xffff0000) >> 16;
92 int i;
101 93
102 priv->base.isr_run(&priv->base, 0, hi | lo); 94 for (i = 0; (hi | lo) && i < 32; i++) {
95 if ((hi | lo) & (1 << i))
96 nouveau_event_trigger(priv->base.events, i);
97 }
103 98
104 nv_wr32(priv, 0x001104, intr); 99 nv_wr32(priv, 0x001104, intr);
105} 100}
106 101
102static void
103nv10_gpio_intr_enable(struct nouveau_event *event, int line)
104{
105 nv_wr32(event->priv, 0x001104, 0x00010001 << line);
106 nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00010001 << line);
107}
108
109static void
110nv10_gpio_intr_disable(struct nouveau_event *event, int line)
111{
112 nv_wr32(event->priv, 0x001104, 0x00010001 << line);
113 nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00000000);
114}
115
107static int 116static int
108nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 117nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
109 struct nouveau_oclass *oclass, void *data, u32 size, 118 struct nouveau_oclass *oclass, void *data, u32 size,
@@ -119,7 +128,9 @@ nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
119 128
120 priv->base.drive = nv10_gpio_drive; 129 priv->base.drive = nv10_gpio_drive;
121 priv->base.sense = nv10_gpio_sense; 130 priv->base.sense = nv10_gpio_sense;
122 priv->base.irq_enable = nv10_gpio_irq_enable; 131 priv->base.events->priv = priv;
132 priv->base.events->enable = nv10_gpio_intr_enable;
133 priv->base.events->disable = nv10_gpio_intr_disable;
123 nv_subdev(priv)->intr = nv10_gpio_intr; 134 nv_subdev(priv)->intr = nv10_gpio_intr;
124 return 0; 135 return 0;
125} 136}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
index dd022a5787b6..cbe609aa237c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
@@ -95,21 +95,12 @@ nv50_gpio_sense(struct nouveau_gpio *gpio, int line)
95} 95}
96 96
97void 97void
98nv50_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on)
99{
100 u32 reg = line < 16 ? 0xe050 : 0xe070;
101 u32 mask = 0x00010001 << (line & 0xf);
102
103 nv_wr32(gpio, reg + 4, mask);
104 nv_mask(gpio, reg + 0, mask, on ? mask : 0);
105}
106
107void
108nv50_gpio_intr(struct nouveau_subdev *subdev) 98nv50_gpio_intr(struct nouveau_subdev *subdev)
109{ 99{
110 struct nv50_gpio_priv *priv = (void *)subdev; 100 struct nv50_gpio_priv *priv = (void *)subdev;
111 u32 intr0, intr1 = 0; 101 u32 intr0, intr1 = 0;
112 u32 hi, lo; 102 u32 hi, lo;
103 int i;
113 104
114 intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050); 105 intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
115 if (nv_device(priv)->chipset >= 0x90) 106 if (nv_device(priv)->chipset >= 0x90)
@@ -117,13 +108,35 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
117 108
118 hi = (intr0 & 0x0000ffff) | (intr1 << 16); 109 hi = (intr0 & 0x0000ffff) | (intr1 << 16);
119 lo = (intr0 >> 16) | (intr1 & 0xffff0000); 110 lo = (intr0 >> 16) | (intr1 & 0xffff0000);
120 priv->base.isr_run(&priv->base, 0, hi | lo); 111
112 for (i = 0; (hi | lo) && i < 32; i++) {
113 if ((hi | lo) & (1 << i))
114 nouveau_event_trigger(priv->base.events, i);
115 }
121 116
122 nv_wr32(priv, 0xe054, intr0); 117 nv_wr32(priv, 0xe054, intr0);
123 if (nv_device(priv)->chipset >= 0x90) 118 if (nv_device(priv)->chipset >= 0x90)
124 nv_wr32(priv, 0xe074, intr1); 119 nv_wr32(priv, 0xe074, intr1);
125} 120}
126 121
122void
123nv50_gpio_intr_enable(struct nouveau_event *event, int line)
124{
125 const u32 addr = line < 16 ? 0xe050 : 0xe070;
126 const u32 mask = 0x00010001 << (line & 0xf);
127 nv_wr32(event->priv, addr + 0x04, mask);
128 nv_mask(event->priv, addr + 0x00, mask, mask);
129}
130
131void
132nv50_gpio_intr_disable(struct nouveau_event *event, int line)
133{
134 const u32 addr = line < 16 ? 0xe050 : 0xe070;
135 const u32 mask = 0x00010001 << (line & 0xf);
136 nv_wr32(event->priv, addr + 0x04, mask);
137 nv_mask(event->priv, addr + 0x00, mask, 0x00000000);
138}
139
127static int 140static int
128nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 141nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
129 struct nouveau_oclass *oclass, void *data, u32 size, 142 struct nouveau_oclass *oclass, void *data, u32 size,
@@ -142,7 +155,9 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
142 priv->base.reset = nv50_gpio_reset; 155 priv->base.reset = nv50_gpio_reset;
143 priv->base.drive = nv50_gpio_drive; 156 priv->base.drive = nv50_gpio_drive;
144 priv->base.sense = nv50_gpio_sense; 157 priv->base.sense = nv50_gpio_sense;
145 priv->base.irq_enable = nv50_gpio_irq_enable; 158 priv->base.events->priv = priv;
159 priv->base.events->enable = nv50_gpio_intr_enable;
160 priv->base.events->disable = nv50_gpio_intr_disable;
146 nv_subdev(priv)->intr = nv50_gpio_intr; 161 nv_subdev(priv)->intr = nv50_gpio_intr;
147 return 0; 162 return 0;
148} 163}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
index bc74199259a2..5ef16a262de7 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
@@ -88,7 +88,9 @@ nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
88 priv->base.reset = nvd0_gpio_reset; 88 priv->base.reset = nvd0_gpio_reset;
89 priv->base.drive = nvd0_gpio_drive; 89 priv->base.drive = nvd0_gpio_drive;
90 priv->base.sense = nvd0_gpio_sense; 90 priv->base.sense = nvd0_gpio_sense;
91 priv->base.irq_enable = nv50_gpio_irq_enable; 91 priv->base.events->priv = priv;
92 priv->base.events->enable = nv50_gpio_intr_enable;
93 priv->base.events->disable = nv50_gpio_intr_disable;
92 nv_subdev(priv)->intr = nv50_gpio_intr; 94 nv_subdev(priv)->intr = nv50_gpio_intr;
93 return 0; 95 return 0;
94} 96}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index a64e8777cbe9..9c4b3f5fba01 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -55,8 +55,6 @@ MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)");
55static int nouveau_duallink = 1; 55static int nouveau_duallink = 1;
56module_param_named(duallink, nouveau_duallink, int, 0400); 56module_param_named(duallink, nouveau_duallink, int, 0400);
57 57
58static void nouveau_connector_hotplug(void *, int);
59
60struct nouveau_encoder * 58struct nouveau_encoder *
61find_encoder(struct drm_connector *connector, int type) 59find_encoder(struct drm_connector *connector, int type)
62{ 60{
@@ -100,22 +98,6 @@ static void
100nouveau_connector_destroy(struct drm_connector *connector) 98nouveau_connector_destroy(struct drm_connector *connector)
101{ 99{
102 struct nouveau_connector *nv_connector = nouveau_connector(connector); 100 struct nouveau_connector *nv_connector = nouveau_connector(connector);
103 struct nouveau_gpio *gpio;
104 struct nouveau_drm *drm;
105 struct drm_device *dev;
106
107 if (!nv_connector)
108 return;
109
110 dev = nv_connector->base.dev;
111 drm = nouveau_drm(dev);
112 gpio = nouveau_gpio(drm->device);
113
114 if (gpio && nv_connector->hpd.func != DCB_GPIO_UNUSED) {
115 gpio->isr_del(gpio, 0, nv_connector->hpd.func, 0xff,
116 nouveau_connector_hotplug, connector);
117 }
118
119 kfree(nv_connector->edid); 101 kfree(nv_connector->edid);
120 drm_sysfs_connector_remove(connector); 102 drm_sysfs_connector_remove(connector);
121 drm_connector_cleanup(connector); 103 drm_connector_cleanup(connector);
@@ -912,6 +894,37 @@ nouveau_connector_funcs_lvds = {
912 .force = nouveau_connector_force 894 .force = nouveau_connector_force
913}; 895};
914 896
897static void
898nouveau_connector_hotplug_work(struct work_struct *work)
899{
900 struct nouveau_connector *nv_connector =
901 container_of(work, struct nouveau_connector, hpd_work);
902 struct drm_connector *connector = &nv_connector->base;
903 struct drm_device *dev = connector->dev;
904 struct nouveau_drm *drm = nouveau_drm(dev);
905 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
906 bool plugged = gpio->get(gpio, 0, nv_connector->hpd.func, 0xff);
907
908 NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un",
909 drm_get_connector_name(connector));
910
911 if (plugged)
912 drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
913 else
914 drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
915
916 drm_helper_hpd_irq_event(dev);
917}
918
919static int
920nouveau_connector_hotplug(struct nouveau_eventh *event, int index)
921{
922 struct nouveau_connector *nv_connector =
923 container_of(event, struct nouveau_connector, hpd_func);
924 schedule_work(&nv_connector->hpd_work);
925 return NVKM_EVENT_KEEP;
926}
927
915static int 928static int
916drm_conntype_from_dcb(enum dcb_connector_type dcb) 929drm_conntype_from_dcb(enum dcb_connector_type dcb)
917{ 930{
@@ -962,6 +975,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
962 return ERR_PTR(-ENOMEM); 975 return ERR_PTR(-ENOMEM);
963 976
964 connector = &nv_connector->base; 977 connector = &nv_connector->base;
978 INIT_WORK(&nv_connector->hpd_work, nouveau_connector_hotplug_work);
965 nv_connector->index = index; 979 nv_connector->index = index;
966 980
967 /* attempt to parse vbios connector type and hotplug gpio */ 981 /* attempt to parse vbios connector type and hotplug gpio */
@@ -978,6 +992,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
978 992
979 ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)], 993 ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)],
980 DCB_GPIO_UNUSED, &nv_connector->hpd); 994 DCB_GPIO_UNUSED, &nv_connector->hpd);
995 nv_connector->hpd_func.func = nouveau_connector_hotplug;
981 if (ret) 996 if (ret)
982 nv_connector->hpd.func = DCB_GPIO_UNUSED; 997 nv_connector->hpd.func = DCB_GPIO_UNUSED;
983 998
@@ -1129,31 +1144,9 @@ nouveau_connector_create(struct drm_device *dev, int index)
1129 } 1144 }
1130 1145
1131 connector->polled = DRM_CONNECTOR_POLL_CONNECT; 1146 connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1132 if (gpio && nv_connector->hpd.func != DCB_GPIO_UNUSED) { 1147 if (nv_connector->hpd.func != DCB_GPIO_UNUSED)
1133 ret = gpio->isr_add(gpio, 0, nv_connector->hpd.func, 0xff, 1148 connector->polled = DRM_CONNECTOR_POLL_HPD;
1134 nouveau_connector_hotplug, connector);
1135 if (ret == 0)
1136 connector->polled = DRM_CONNECTOR_POLL_HPD;
1137 }
1138 1149
1139 drm_sysfs_connector_add(connector); 1150 drm_sysfs_connector_add(connector);
1140 return connector; 1151 return connector;
1141} 1152}
1142
1143static void
1144nouveau_connector_hotplug(void *data, int plugged)
1145{
1146 struct drm_connector *connector = data;
1147 struct drm_device *dev = connector->dev;
1148 struct nouveau_drm *drm = nouveau_drm(dev);
1149
1150 NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un",
1151 drm_get_connector_name(connector));
1152
1153 if (plugged)
1154 drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
1155 else
1156 drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
1157
1158 drm_helper_hpd_irq_event(dev);
1159}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index f37250c8469d..6e399aad491a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -30,6 +30,8 @@
30#include <drm/drm_edid.h> 30#include <drm/drm_edid.h>
31#include "nouveau_crtc.h" 31#include "nouveau_crtc.h"
32 32
33#include <core/event.h>
34
33#include <subdev/bios.h> 35#include <subdev/bios.h>
34#include <subdev/bios/gpio.h> 36#include <subdev/bios/gpio.h>
35 37
@@ -62,10 +64,13 @@ enum nouveau_dithering_depth {
62struct nouveau_connector { 64struct nouveau_connector {
63 struct drm_connector base; 65 struct drm_connector base;
64 enum dcb_connector_type type; 66 enum dcb_connector_type type;
65 struct dcb_gpio_func hpd;
66 u8 index; 67 u8 index;
67 u8 *dcb; 68 u8 *dcb;
68 69
70 struct dcb_gpio_func hpd;
71 struct work_struct hpd_work;
72 struct nouveau_eventh hpd_func;
73
69 int dithering_mode; 74 int dithering_mode;
70 int dithering_depth; 75 int dithering_depth;
71 int scaling_mode; 76 int scaling_mode;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index a698e79f99d9..78fc5aa5f5dc 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -233,8 +233,10 @@ nouveau_display_init(struct drm_device *dev)
233 /* enable hotplug interrupts */ 233 /* enable hotplug interrupts */
234 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 234 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
235 struct nouveau_connector *conn = nouveau_connector(connector); 235 struct nouveau_connector *conn = nouveau_connector(connector);
236 if (gpio) 236 if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
237 gpio->irq(gpio, 0, conn->hpd.func, 0xff, true); 237 nouveau_event_get(gpio->events, conn->hpd.line,
238 &conn->hpd_func);
239 }
238 } 240 }
239 241
240 return ret; 242 return ret;
@@ -251,8 +253,10 @@ nouveau_display_fini(struct drm_device *dev)
251 /* disable hotplug interrupts */ 253 /* disable hotplug interrupts */
252 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 254 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
253 struct nouveau_connector *conn = nouveau_connector(connector); 255 struct nouveau_connector *conn = nouveau_connector(connector);
254 if (gpio) 256 if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
255 gpio->irq(gpio, 0, conn->hpd.func, 0xff, false); 257 nouveau_event_put(gpio->events, conn->hpd.line,
258 &conn->hpd_func);
259 }
256 } 260 }
257 261
258 drm_kms_helper_poll_disable(dev); 262 drm_kms_helper_poll_disable(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index c273c2afed10..a87c3674157f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -260,7 +260,8 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
260 * we take during link training (DP_SET_POWER is one), we need 260 * we take during link training (DP_SET_POWER is one), we need
261 * to ignore them for the moment to avoid races. 261 * to ignore them for the moment to avoid races.
262 */ 262 */
263 gpio->irq(gpio, 0, nv_connector->hpd.func, 0xff, false); 263 nouveau_event_put(gpio->events, nv_connector->hpd.line,
264 &nv_connector->hpd_func);
264 265
265 /* enable down-spreading and execute pre-train script from vbios */ 266 /* enable down-spreading and execute pre-train script from vbios */
266 dp_link_train_init(dev, &dp, nv_encoder->dp.dpcd[3] & 1); 267 dp_link_train_init(dev, &dp, nv_encoder->dp.dpcd[3] & 1);
@@ -300,7 +301,8 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
300 dp_link_train_fini(dev, &dp); 301 dp_link_train_fini(dev, &dp);
301 302
302 /* re-enable hotplug detect */ 303 /* re-enable hotplug detect */
303 gpio->irq(gpio, 0, nv_connector->hpd.func, 0xff, true); 304 nouveau_event_get(gpio->events, nv_connector->hpd.line,
305 &nv_connector->hpd_func);
304 return true; 306 return true;
305} 307}
306 308