diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-02-02 21:56:16 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-02-20 01:00:50 -0500 |
commit | 4f47643dbb4c345c5beebe53588682a7ff2c872a (patch) | |
tree | 824b98893e562bedab63d6987c1d248332b45f3f /drivers/gpu/drm/nouveau | |
parent | 0f0800661a125ddb038462570c869fe6f8ab5737 (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.h | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/gpio/base.c | 137 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c | 39 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_connector.c | 77 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_connector.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_dp.c | 6 |
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 @@ | |||
10 | struct nouveau_gpio { | 11 | struct 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 | ||
37 | static inline struct nouveau_gpio * | 28 | static 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 | ||
50 | int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, | 43 | int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, |
51 | struct nouveau_oclass *, int, int, void **); | 44 | struct nouveau_oclass *, int, int, void **); |
52 | int nouveau_gpio_init(struct nouveau_gpio *); | 45 | void _nouveau_gpio_dtor(struct nouveau_object *); |
46 | int nouveau_gpio_init(struct nouveau_gpio *); | ||
53 | 47 | ||
54 | extern struct nouveau_oclass nv10_gpio_oclass; | 48 | extern struct nouveau_oclass nv10_gpio_oclass; |
55 | extern struct nouveau_oclass nv50_gpio_oclass; | 49 | extern struct nouveau_oclass nv50_gpio_oclass; |
@@ -59,6 +53,7 @@ void nv50_gpio_dtor(struct nouveau_object *); | |||
59 | int nv50_gpio_init(struct nouveau_object *); | 53 | int nv50_gpio_init(struct nouveau_object *); |
60 | int nv50_gpio_fini(struct nouveau_object *, bool); | 54 | int nv50_gpio_fini(struct nouveau_object *, bool); |
61 | void nv50_gpio_intr(struct nouveau_subdev *); | 55 | void nv50_gpio_intr(struct nouveau_subdev *); |
62 | void nv50_gpio_irq_enable(struct nouveau_gpio *, int line, bool); | 56 | void nv50_gpio_intr_enable(struct nouveau_event *, int line); |
57 | void 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 | ||
105 | static int | 105 | void |
106 | nouveau_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 | |||
122 | struct 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 | |||
133 | static void | ||
134 | nouveau_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 | |||
151 | static void | ||
152 | nouveau_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 | |||
171 | static int | ||
172 | nouveau_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 | |||
201 | static void | ||
202 | nouveau_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 | ||
230 | int | 113 | int |
@@ -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 | ||
85 | static void | 85 | static void |
86 | nv10_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 | |||
94 | static void | ||
95 | nv10_gpio_intr(struct nouveau_subdev *subdev) | 86 | nv10_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 | ||
102 | static void | ||
103 | nv10_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 | |||
109 | static void | ||
110 | nv10_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 | |||
107 | static int | 116 | static int |
108 | nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 117 | nv10_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 | ||
97 | void | 97 | void |
98 | nv50_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 | |||
107 | void | ||
108 | nv50_gpio_intr(struct nouveau_subdev *subdev) | 98 | nv50_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 | ||
122 | void | ||
123 | nv50_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 | |||
131 | void | ||
132 | nv50_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 | |||
127 | static int | 140 | static int |
128 | nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 141 | nv50_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)"); | |||
55 | static int nouveau_duallink = 1; | 55 | static int nouveau_duallink = 1; |
56 | module_param_named(duallink, nouveau_duallink, int, 0400); | 56 | module_param_named(duallink, nouveau_duallink, int, 0400); |
57 | 57 | ||
58 | static void nouveau_connector_hotplug(void *, int); | ||
59 | |||
60 | struct nouveau_encoder * | 58 | struct nouveau_encoder * |
61 | find_encoder(struct drm_connector *connector, int type) | 59 | find_encoder(struct drm_connector *connector, int type) |
62 | { | 60 | { |
@@ -100,22 +98,6 @@ static void | |||
100 | nouveau_connector_destroy(struct drm_connector *connector) | 98 | nouveau_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 | ||
897 | static void | ||
898 | nouveau_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 | |||
919 | static int | ||
920 | nouveau_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 | |||
915 | static int | 928 | static int |
916 | drm_conntype_from_dcb(enum dcb_connector_type dcb) | 929 | drm_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 | |||
1143 | static void | ||
1144 | nouveau_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 { | |||
62 | struct nouveau_connector { | 64 | struct 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 | ||