aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-07-09 22:20:17 -0400
committerBen Skeggs <bskeggs@redhat.com>2012-10-02 23:12:45 -0400
commite0996aea4c349ba302b63203b7d5cab6034dbdca (patch)
tree5b46c04d6e2588ee9b6a9065ba074f6bd37c5812 /drivers
parentcd42439da48529a3cd6f957b226fc627a64fb771 (diff)
drm/nouveau/gpio: port gpio to subdev interfaces
v2: Ben Skeggs <bskeggs@redhat.com> - rebase on top of v3.6-rc6 with gpio reset patch integrated already Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/nouveau/Makefile3
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h19
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h26
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/gpio.h113
-rw-r--r--drivers/gpu/drm/nouveau/core/os.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c135
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c114
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv10.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv20.c5
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv30.c6
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv40.c17
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv50.c15
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nve0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/base.c329
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c116
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c179
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c104
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/base.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h15
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_compat.c80
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_compat.h11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h27
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mxm.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c42
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_volt.c5
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dac.c3
-rw-r--r--drivers/gpu/drm/nouveau/nv17_tv.c3
33 files changed, 933 insertions, 503 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index d10ec93c5ad..414b2e8b810 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -20,6 +20,8 @@ nouveau-y += core/core/subdev.o
20 20
21nouveau-y += core/subdev/bios/base.o 21nouveau-y += core/subdev/bios/base.o
22nouveau-y += core/subdev/bios/bit.o 22nouveau-y += core/subdev/bios/bit.o
23nouveau-y += core/subdev/bios/dcb.o
24nouveau-y += core/subdev/bios/gpio.o
23nouveau-y += core/subdev/device/base.o 25nouveau-y += core/subdev/device/base.o
24nouveau-y += core/subdev/device/nv04.o 26nouveau-y += core/subdev/device/nv04.o
25nouveau-y += core/subdev/device/nv10.o 27nouveau-y += core/subdev/device/nv10.o
@@ -41,6 +43,7 @@ nouveau-y += core/subdev/fb/nvc0_vram.o
41nouveau-y += core/subdev/gpio/base.o 43nouveau-y += core/subdev/gpio/base.o
42nouveau-y += core/subdev/gpio/nv10.o 44nouveau-y += core/subdev/gpio/nv10.o
43nouveau-y += core/subdev/gpio/nv50.o 45nouveau-y += core/subdev/gpio/nv50.o
46nouveau-y += core/subdev/gpio/nvd0.o
44nouveau-y += core/subdev/i2c/base.o 47nouveau-y += core/subdev/i2c/base.o
45nouveau-y += core/subdev/instmem/nv04.o 48nouveau-y += core/subdev/instmem/nv04.o
46nouveau-y += core/subdev/instmem/nv50.o 49nouveau-y += core/subdev/instmem/nv50.o
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h
new file mode 100644
index 00000000000..7000dcf2ae9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h
@@ -0,0 +1,19 @@
1#ifndef __NVBIOS_DCB_H__
2#define __NVBIOS_DCB_H__
3
4enum dcb_output_type {
5 DCB_OUTPUT_ANALOG = 0x0,
6 DCB_OUTPUT_TV = 0x1,
7 DCB_OUTPUT_TMDS = 0x2,
8 DCB_OUTPUT_LVDS = 0x3,
9 DCB_OUTPUT_DP = 0x4,
10 DCB_OUTPUT_EOL = 0xe,
11 DCB_OUTPUT_UNUSED = 0xf,
12};
13
14u16 dcb_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len);
15u16 dcb_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len);
16int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec)
17 (struct nouveau_bios *, void *, int index, u16 entry));
18
19#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
new file mode 100644
index 00000000000..e9789cf411c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
@@ -0,0 +1,26 @@
1#ifndef __NVBIOS_GPIO_H__
2#define __NVBIOS_GPIO_H__
3
4struct nouveau_bios;
5
6enum dcb_gpio_func_name {
7 DCB_GPIO_PANEL_POWER = 0x01,
8 DCB_GPIO_TVDAC0 = 0x0c,
9 DCB_GPIO_TVDAC1 = 0x2d,
10 DCB_GPIO_PWM_FAN = 0x09,
11 DCB_GPIO_FAN_SENSE = 0x3d,
12 DCB_GPIO_UNUSED = 0xff
13};
14
15struct dcb_gpio_func {
16 u8 func;
17 u8 line;
18 u8 log[2];
19};
20
21u16 dcb_gpio_table(struct nouveau_bios *);
22u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver);
23int dcb_gpio_parse(struct nouveau_bios *, int idx, u8 func, u8 line,
24 struct dcb_gpio_func *);
25
26#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
index 64c5cb077ac..9ea2b12cc15 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
@@ -1,71 +1,64 @@
1/*
2 * Copyright 2011 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23#ifndef __NOUVEAU_GPIO_H__ 1#ifndef __NOUVEAU_GPIO_H__
24#define __NOUVEAU_GPIO_H__ 2#define __NOUVEAU_GPIO_H__
25 3
26struct gpio_func { 4#include <core/subdev.h>
27 u8 func; 5#include <core/device.h>
28 u8 line;
29 u8 log[2];
30};
31 6
32/* nouveau_gpio.c */ 7#include <subdev/bios.h>
33int nouveau_gpio_create(struct drm_device *); 8#include <subdev/bios/gpio.h>
34void nouveau_gpio_destroy(struct drm_device *);
35int nouveau_gpio_init(struct drm_device *);
36void nouveau_gpio_fini(struct drm_device *);
37void nouveau_gpio_reset(struct drm_device *);
38int nouveau_gpio_drive(struct drm_device *, int idx, int line,
39 int dir, int out);
40int nouveau_gpio_sense(struct drm_device *, int idx, int line);
41int nouveau_gpio_find(struct drm_device *, int idx, u8 tag, u8 line,
42 struct gpio_func *);
43int nouveau_gpio_set(struct drm_device *, int idx, u8 tag, u8 line, int state);
44int nouveau_gpio_get(struct drm_device *, int idx, u8 tag, u8 line);
45int nouveau_gpio_irq(struct drm_device *, int idx, u8 tag, u8 line, bool on);
46void nouveau_gpio_isr(struct drm_device *, int idx, u32 mask);
47int nouveau_gpio_isr_add(struct drm_device *, int idx, u8 tag, u8 line,
48 void (*)(void *, int state), void *data);
49void nouveau_gpio_isr_del(struct drm_device *, int idx, u8 tag, u8 line,
50 void (*)(void *, int state), void *data);
51 9
52static inline bool 10struct nouveau_gpio {
53nouveau_gpio_func_valid(struct drm_device *dev, u8 tag) 11 struct nouveau_subdev base;
54{
55 struct gpio_func func;
56 return (nouveau_gpio_find(dev, 0, tag, 0xff, &func)) == 0;
57}
58 12
59static inline int 13 /* hardware interfaces */
60nouveau_gpio_func_set(struct drm_device *dev, u8 tag, int state) 14 void (*reset)(struct nouveau_gpio *);
61{ 15 int (*drive)(struct nouveau_gpio *, int line, int dir, int out);
62 return nouveau_gpio_set(dev, 0, tag, 0xff, state); 16 int (*sense)(struct nouveau_gpio *, int line);
63} 17 void (*irq_enable)(struct nouveau_gpio *, int line, bool);
18
19 /* software interfaces */
20 int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
21 struct dcb_gpio_func *);
22 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);
24 int (*irq)(struct nouveau_gpio *, int idx, u8 tag, u8 line, bool on);
64 25
65static inline int 26 /* interrupt handling */
66nouveau_gpio_func_get(struct drm_device *dev, u8 tag) 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};
36
37static inline struct nouveau_gpio *
38nouveau_gpio(void *obj)
67{ 39{
68 return nouveau_gpio_get(dev, 0, tag, 0xff); 40 return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO];
69} 41}
70 42
43#define nouveau_gpio_create(p,e,o,d) \
44 nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d)
45#define nouveau_gpio_destroy(p) \
46 nouveau_subdev_destroy(&(p)->base)
47#define nouveau_gpio_fini(p,s) \
48 nouveau_subdev_fini(&(p)->base, (s))
49
50int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
51 struct nouveau_oclass *, int, void **);
52int nouveau_gpio_init(struct nouveau_gpio *);
53
54extern struct nouveau_oclass nv10_gpio_oclass;
55extern struct nouveau_oclass nv50_gpio_oclass;
56extern struct nouveau_oclass nvd0_gpio_oclass;
57
58void nv50_gpio_dtor(struct nouveau_object *);
59int nv50_gpio_init(struct nouveau_object *);
60int nv50_gpio_fini(struct nouveau_object *, bool);
61void nv50_gpio_intr(struct nouveau_subdev *);
62void nv50_gpio_irq_enable(struct nouveau_gpio *, int line, bool);
63
71#endif 64#endif
diff --git a/drivers/gpu/drm/nouveau/core/os.h b/drivers/gpu/drm/nouveau/core/os.h
index 76bdb0efc1e..661b037729e 100644
--- a/drivers/gpu/drm/nouveau/core/os.h
+++ b/drivers/gpu/drm/nouveau/core/os.h
@@ -15,6 +15,7 @@
15#include <linux/io-mapping.h> 15#include <linux/io-mapping.h>
16#include <linux/vmalloc.h> 16#include <linux/vmalloc.h>
17#include <linux/acpi.h> 17#include <linux/acpi.h>
18#include <linux/dmi.h>
18 19
19#include <asm/unaligned.h> 20#include <asm/unaligned.h>
20 21
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
new file mode 100644
index 00000000000..9ed6e728a94
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
@@ -0,0 +1,135 @@
1/*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
25#include "core/device.h"
26
27#include "subdev/bios.h"
28#include "subdev/bios/dcb.h"
29
30u16
31dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
32{
33 struct nouveau_device *device = nv_device(bios);
34 u16 dcb = 0x0000;
35
36 if (device->card_type > NV_04)
37 dcb = nv_ro16(bios, 0x36);
38 if (!dcb) {
39 nv_warn(bios, "DCB table not found\n");
40 return dcb;
41 }
42
43 *ver = nv_ro08(bios, dcb);
44
45 if (*ver >= 0x41) {
46 nv_warn(bios, "DCB *ver 0x%02x unknown\n", *ver);
47 return 0x0000;
48 } else
49 if (*ver >= 0x30) {
50 if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) {
51 *hdr = nv_ro08(bios, dcb + 1);
52 *cnt = nv_ro08(bios, dcb + 2);
53 *len = nv_ro08(bios, dcb + 3);
54 return dcb;
55 }
56 } else
57 if (*ver >= 0x20) {
58 if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) {
59 u16 i2c = nv_ro16(bios, dcb + 2);
60 *hdr = 8;
61 *cnt = (i2c - dcb) / 8;
62 *len = 8;
63 return dcb;
64 }
65 } else
66 if (*ver >= 0x15) {
67 if (!nv_strncmp(bios, dcb - 7, 7, "DEV_REC")) {
68 u16 i2c = nv_ro16(bios, dcb + 2);
69 *hdr = 4;
70 *cnt = (i2c - dcb) / 10;
71 *len = 10;
72 return dcb;
73 }
74 } else {
75 /*
76 * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but
77 * always has the same single (crt) entry, even when tv-out
78 * present, so the conclusion is this version cannot really
79 * be used.
80 *
81 * v1.2 tables (some NV6/10, and NV15+) normally have the
82 * same 5 entries, which are not specific to the card and so
83 * no use.
84 *
85 * v1.2 does have an I2C table that read_dcb_i2c_table can
86 * handle, but cards exist (nv11 in #14821) with a bad i2c
87 * table pointer, so use the indices parsed in
88 * parse_bmp_structure.
89 *
90 * v1.1 (NV5+, maybe some NV4) is entirely unhelpful
91 */
92 nv_warn(bios, "DCB contains no useful data\n");
93 return 0x0000;
94 }
95
96 nv_warn(bios, "DCB header validation failed\n");
97 return 0x0000;
98}
99
100u16
101dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
102{
103 u8 hdr, cnt;
104 u16 dcb = dcb_table(bios, ver, &hdr, &cnt, len);
105 if (dcb && idx < cnt)
106 return dcb + hdr + (idx * *len);
107 return 0x0000;
108}
109
110int
111dcb_outp_foreach(struct nouveau_bios *bios, void *data,
112 int (*exec)(struct nouveau_bios *, void *, int, u16))
113{
114 int ret, idx = -1;
115 u8 ver, len;
116 u16 outp;
117
118 while ((outp = dcb_outp(bios, ++idx, &ver, &len))) {
119 if (nv_ro32(bios, outp) == 0x00000000)
120 break; /* seen on an NV11 with DCB v1.5 */
121 if (nv_ro32(bios, outp) == 0xffffffff)
122 break; /* seen on an NV17 with DCB v2.0 */
123
124 if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED)
125 continue;
126 if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL)
127 break;
128
129 ret = exec(bios, data, idx, outp);
130 if (ret)
131 return ret;
132 }
133
134 return 0;
135}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
new file mode 100644
index 00000000000..718267d84c7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
@@ -0,0 +1,114 @@
1/*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
25#include <subdev/bios.h>
26#include <subdev/bios/dcb.h>
27#include <subdev/bios/gpio.h>
28
29u16
30dcb_gpio_table(struct nouveau_bios *bios)
31{
32 u8 ver, hdr, cnt, len;
33 u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len);
34 if (dcb) {
35 if (ver >= 0x30 && hdr >= 0x0c)
36 return nv_ro16(bios, dcb + 0x0a);
37 if (ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13)
38 return nv_ro16(bios, dcb - 0x0f);
39 }
40 return 0x0000;
41}
42
43u16
44dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver)
45{
46 u16 gpio = dcb_gpio_table(bios);
47 if (gpio) {
48 *ver = nv_ro08(bios, gpio);
49 if (*ver < 0x30 && ent < nv_ro08(bios, gpio + 2))
50 return gpio + 3 + (ent * nv_ro08(bios, gpio + 1));
51 else if (ent < nv_ro08(bios, gpio + 2))
52 return gpio + nv_ro08(bios, gpio + 1) +
53 (ent * nv_ro08(bios, gpio + 3));
54 }
55 return 0x0000;
56}
57
58int
59dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line,
60 struct dcb_gpio_func *gpio)
61{
62 u8 ver, hdr, cnt, len;
63 u16 entry;
64 int i = -1;
65
66 while ((entry = dcb_gpio_entry(bios, idx, ++i, &ver))) {
67 if (ver < 0x40) {
68 u16 data = nv_ro16(bios, entry);
69 *gpio = (struct dcb_gpio_func) {
70 .line = (data & 0x001f) >> 0,
71 .func = (data & 0x07e0) >> 5,
72 .log[0] = (data & 0x1800) >> 11,
73 .log[1] = (data & 0x6000) >> 13,
74 };
75 } else
76 if (ver < 0x41) {
77 u32 data = nv_ro32(bios, entry);
78 *gpio = (struct dcb_gpio_func) {
79 .line = (data & 0x0000001f) >> 0,
80 .func = (data & 0x0000ff00) >> 8,
81 .log[0] = (data & 0x18000000) >> 27,
82 .log[1] = (data & 0x60000000) >> 29,
83 };
84 } else {
85 u32 data = nv_ro32(bios, entry + 0);
86 u8 data1 = nv_ro32(bios, entry + 4);
87 *gpio = (struct dcb_gpio_func) {
88 .line = (data & 0x0000003f) >> 0,
89 .func = (data & 0x0000ff00) >> 8,
90 .log[0] = (data1 & 0x30) >> 4,
91 .log[1] = (data1 & 0xc0) >> 6,
92 };
93 }
94
95 if ((line == 0xff || line == gpio->line) &&
96 (func == 0xff || func == gpio->func))
97 return 0;
98 }
99
100 /* DCB 2.2, fixed TVDAC GPIO data */
101 if ((entry = dcb_table(bios, &ver, &hdr, &cnt, &len)) && ver >= 0x22) {
102 if (func == DCB_GPIO_TVDAC0) {
103 *gpio = (struct dcb_gpio_func) {
104 .func = DCB_GPIO_TVDAC0,
105 .line = nv_ro08(bios, entry - 4) >> 4,
106 .log[0] = !!(nv_ro08(bios, entry - 5) & 2),
107 .log[1] = !(nv_ro08(bios, entry - 5) & 2),
108 };
109 return 0;
110 }
111 }
112
113 return -EINVAL;
114}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c
index f9e42887518..c0c40cddaa2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c
@@ -24,6 +24,7 @@
24 24
25#include <subdev/device.h> 25#include <subdev/device.h>
26#include <subdev/bios.h> 26#include <subdev/bios.h>
27#include <subdev/gpio.h>
27 28
28int 29int
29nv10_identify(struct nouveau_device *device) 30nv10_identify(struct nouveau_device *device)
@@ -31,27 +32,35 @@ nv10_identify(struct nouveau_device *device)
31 switch (device->chipset) { 32 switch (device->chipset) {
32 case 0x10: 33 case 0x10:
33 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 34 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
35 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
34 break; 36 break;
35 case 0x15: 37 case 0x15:
36 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 38 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
39 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
37 break; 40 break;
38 case 0x16: 41 case 0x16:
39 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
43 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
40 break; 44 break;
41 case 0x1a: 45 case 0x1a:
42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 46 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
47 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
43 break; 48 break;
44 case 0x11: 49 case 0x11:
45 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 50 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
51 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
46 break; 52 break;
47 case 0x17: 53 case 0x17:
48 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 54 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
55 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
49 break; 56 break;
50 case 0x1f: 57 case 0x1f:
51 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 58 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
59 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
52 break; 60 break;
53 case 0x18: 61 case 0x18:
54 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 62 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
63 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
55 break; 64 break;
56 default: 65 default:
57 nv_fatal(device, "unknown Celsius chipset\n"); 66 nv_fatal(device, "unknown Celsius chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
index b5dfb7e8483..1215e3ff47f 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
@@ -24,6 +24,7 @@
24 24
25#include <subdev/device.h> 25#include <subdev/device.h>
26#include <subdev/bios.h> 26#include <subdev/bios.h>
27#include <subdev/gpio.h>
27 28
28int 29int
29nv20_identify(struct nouveau_device *device) 30nv20_identify(struct nouveau_device *device)
@@ -31,15 +32,19 @@ nv20_identify(struct nouveau_device *device)
31 switch (device->chipset) { 32 switch (device->chipset) {
32 case 0x20: 33 case 0x20:
33 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 34 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
35 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
34 break; 36 break;
35 case 0x25: 37 case 0x25:
36 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 38 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
39 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
37 break; 40 break;
38 case 0x28: 41 case 0x28:
39 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
43 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
40 break; 44 break;
41 case 0x2a: 45 case 0x2a:
42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 46 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
47 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
43 break; 48 break;
44 default: 49 default:
45 nv_fatal(device, "unknown Kelvin chipset\n"); 50 nv_fatal(device, "unknown Kelvin chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c
index b2e50e39dc8..43eb94e7768 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c
@@ -24,6 +24,7 @@
24 24
25#include <subdev/device.h> 25#include <subdev/device.h>
26#include <subdev/bios.h> 26#include <subdev/bios.h>
27#include <subdev/gpio.h>
27 28
28int 29int
29nv30_identify(struct nouveau_device *device) 30nv30_identify(struct nouveau_device *device)
@@ -31,18 +32,23 @@ nv30_identify(struct nouveau_device *device)
31 switch (device->chipset) { 32 switch (device->chipset) {
32 case 0x30: 33 case 0x30:
33 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 34 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
35 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
34 break; 36 break;
35 case 0x35: 37 case 0x35:
36 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 38 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
39 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
37 break; 40 break;
38 case 0x31: 41 case 0x31:
39 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
43 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
40 break; 44 break;
41 case 0x36: 45 case 0x36:
42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 46 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
47 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
43 break; 48 break;
44 case 0x34: 49 case 0x34:
45 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 50 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
51 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
46 break; 52 break;
47 default: 53 default:
48 nv_fatal(device, "unknown Rankine chipset\n"); 54 nv_fatal(device, "unknown Rankine chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
index 4a3e3a857a0..7c10a3c68d5 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
@@ -24,6 +24,7 @@
24 24
25#include <subdev/device.h> 25#include <subdev/device.h>
26#include <subdev/bios.h> 26#include <subdev/bios.h>
27#include <subdev/gpio.h>
27 28
28int 29int
29nv40_identify(struct nouveau_device *device) 30nv40_identify(struct nouveau_device *device)
@@ -31,51 +32,67 @@ nv40_identify(struct nouveau_device *device)
31 switch (device->chipset) { 32 switch (device->chipset) {
32 case 0x40: 33 case 0x40:
33 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 34 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
35 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
34 break; 36 break;
35 case 0x41: 37 case 0x41:
36 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 38 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
39 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
37 break; 40 break;
38 case 0x42: 41 case 0x42:
39 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
43 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
40 break; 44 break;
41 case 0x43: 45 case 0x43:
42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 46 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
47 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
43 break; 48 break;
44 case 0x45: 49 case 0x45:
45 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 50 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
51 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
46 break; 52 break;
47 case 0x47: 53 case 0x47:
48 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 54 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
55 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
49 break; 56 break;
50 case 0x49: 57 case 0x49:
51 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 58 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
59 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
52 break; 60 break;
53 case 0x4b: 61 case 0x4b:
54 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 62 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
63 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
55 break; 64 break;
56 case 0x44: 65 case 0x44:
57 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 66 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
67 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
58 break; 68 break;
59 case 0x46: 69 case 0x46:
60 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 70 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
71 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
61 break; 72 break;
62 case 0x4a: 73 case 0x4a:
63 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 74 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
75 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
64 break; 76 break;
65 case 0x4c: 77 case 0x4c:
66 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 78 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
79 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
67 break; 80 break;
68 case 0x4e: 81 case 0x4e:
69 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 82 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
83 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
70 break; 84 break;
71 case 0x63: 85 case 0x63:
72 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 86 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
87 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
73 break; 88 break;
74 case 0x67: 89 case 0x67:
75 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 90 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
91 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
76 break; 92 break;
77 case 0x68: 93 case 0x68:
78 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 94 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
95 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
79 break; 96 break;
80 default: 97 default:
81 nv_fatal(device, "unknown Curie chipset\n"); 98 nv_fatal(device, "unknown Curie chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
index 018c7115767..581dcf19988 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
@@ -24,6 +24,7 @@
24 24
25#include <subdev/device.h> 25#include <subdev/device.h>
26#include <subdev/bios.h> 26#include <subdev/bios.h>
27#include <subdev/gpio.h>
27 28
28int 29int
29nv50_identify(struct nouveau_device *device) 30nv50_identify(struct nouveau_device *device)
@@ -31,45 +32,59 @@ nv50_identify(struct nouveau_device *device)
31 switch (device->chipset) { 32 switch (device->chipset) {
32 case 0x50: 33 case 0x50:
33 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 34 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
35 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
34 break; 36 break;
35 case 0x84: 37 case 0x84:
36 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 38 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
39 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
37 break; 40 break;
38 case 0x86: 41 case 0x86:
39 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
43 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
40 break; 44 break;
41 case 0x92: 45 case 0x92:
42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 46 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
47 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
43 break; 48 break;
44 case 0x94: 49 case 0x94:
45 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 50 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
51 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
46 break; 52 break;
47 case 0x96: 53 case 0x96:
48 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 54 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
55 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
49 break; 56 break;
50 case 0x98: 57 case 0x98:
51 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 58 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
59 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
52 break; 60 break;
53 case 0xa0: 61 case 0xa0:
54 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 62 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
63 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
55 break; 64 break;
56 case 0xaa: 65 case 0xaa:
57 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 66 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
67 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
58 break; 68 break;
59 case 0xac: 69 case 0xac:
60 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 70 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
71 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
61 break; 72 break;
62 case 0xa3: 73 case 0xa3:
63 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 74 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
75 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
64 break; 76 break;
65 case 0xa5: 77 case 0xa5:
66 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 78 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
79 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
67 break; 80 break;
68 case 0xa8: 81 case 0xa8:
69 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 82 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
83 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
70 break; 84 break;
71 case 0xaf: 85 case 0xaf:
72 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 86 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
87 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
73 break; 88 break;
74 default: 89 default:
75 nv_fatal(device, "unknown Tesla chipset\n"); 90 nv_fatal(device, "unknown Tesla chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
index 0e8127793c5..df31111965c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
@@ -24,6 +24,7 @@
24 24
25#include <subdev/device.h> 25#include <subdev/device.h>
26#include <subdev/bios.h> 26#include <subdev/bios.h>
27#include <subdev/gpio.h>
27 28
28int 29int
29nvc0_identify(struct nouveau_device *device) 30nvc0_identify(struct nouveau_device *device)
@@ -31,27 +32,35 @@ nvc0_identify(struct nouveau_device *device)
31 switch (device->chipset) { 32 switch (device->chipset) {
32 case 0xc0: 33 case 0xc0:
33 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 34 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
35 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
34 break; 36 break;
35 case 0xc4: 37 case 0xc4:
36 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 38 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
39 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
37 break; 40 break;
38 case 0xc3: 41 case 0xc3:
39 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
43 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
40 break; 44 break;
41 case 0xce: 45 case 0xce:
42 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 46 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
47 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
43 break; 48 break;
44 case 0xcf: 49 case 0xcf:
45 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 50 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
51 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
46 break; 52 break;
47 case 0xc1: 53 case 0xc1:
48 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 54 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
55 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
49 break; 56 break;
50 case 0xc8: 57 case 0xc8:
51 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 58 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
59 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
52 break; 60 break;
53 case 0xd9: 61 case 0xd9:
54 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 62 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
63 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
55 break; 64 break;
56 default: 65 default:
57 nv_fatal(device, "unknown Fermi chipset\n"); 66 nv_fatal(device, "unknown Fermi chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
index 15cae4364e9..d321cb4ec13 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
@@ -24,6 +24,7 @@
24 24
25#include <subdev/device.h> 25#include <subdev/device.h>
26#include <subdev/bios.h> 26#include <subdev/bios.h>
27#include <subdev/gpio.h>
27 28
28int 29int
29nve0_identify(struct nouveau_device *device) 30nve0_identify(struct nouveau_device *device)
@@ -31,9 +32,11 @@ nve0_identify(struct nouveau_device *device)
31 switch (device->chipset) { 32 switch (device->chipset) {
32 case 0xe4: 33 case 0xe4:
33 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 34 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
35 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
34 break; 36 break;
35 case 0xe7: 37 case 0xe7:
36 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 38 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
39 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
37 break; 40 break;
38 default: 41 default:
39 nv_fatal(device, "unknown Kepler chipset\n"); 42 nv_fatal(device, "unknown Kepler chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
index 2c48309b0e1..abb135f7495 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
@@ -22,114 +22,37 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24 24
25#include "drmP.h"
26#include "nouveau_drv.h"
27#include <subdev/i2c.h>
28#include <subdev/gpio.h> 25#include <subdev/gpio.h>
26#include <subdev/bios.h>
27#include <subdev/bios/gpio.h>
29 28
30static u8 * 29static int
31dcb_gpio_table(struct drm_device *dev) 30nouveau_gpio_drive(struct nouveau_gpio *gpio,
31 int idx, int line, int dir, int out)
32{ 32{
33 u8 *dcb = dcb_table(dev); 33 return gpio->drive ? gpio->drive(gpio, line, dir, out) : -ENODEV;
34 if (dcb) {
35 if (dcb[0] >= 0x30 && dcb[1] >= 0x0c)
36 return ROMPTR(dev, dcb[0x0a]);
37 if (dcb[0] >= 0x22 && dcb[-1] >= 0x13)
38 return ROMPTR(dev, dcb[-15]);
39 }
40 return NULL;
41}
42
43static u8 *
44dcb_gpio_entry(struct drm_device *dev, int idx, int ent, u8 *version)
45{
46 u8 *table = dcb_gpio_table(dev);
47 if (table) {
48 *version = table[0];
49 if (*version < 0x30 && ent < table[2])
50 return table + 3 + (ent * table[1]);
51 else if (ent < table[2])
52 return table + table[1] + (ent * table[3]);
53 }
54 return NULL;
55} 34}
56 35
57int 36static int
58nouveau_gpio_drive(struct drm_device *dev, int idx, int line, int dir, int out) 37nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line)
59{ 38{
60 struct drm_nouveau_private *dev_priv = dev->dev_private; 39 return gpio->sense ? gpio->sense(gpio, line) : -ENODEV;
61 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
62
63 return pgpio->drive ? pgpio->drive(dev, line, dir, out) : -ENODEV;
64} 40}
65 41
66int 42static int
67nouveau_gpio_sense(struct drm_device *dev, int idx, int line) 43nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
44 struct dcb_gpio_func *func)
68{ 45{
69 struct drm_nouveau_private *dev_priv = dev->dev_private; 46 if (line == 0xff && tag == 0xff)
70 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
71
72 return pgpio->sense ? pgpio->sense(dev, line) : -ENODEV;
73}
74
75int
76nouveau_gpio_find(struct drm_device *dev, int idx, u8 func, u8 line,
77 struct gpio_func *gpio)
78{
79 u8 *table, *entry, version;
80 int i = -1;
81
82 if (line == 0xff && func == 0xff)
83 return -EINVAL; 47 return -EINVAL;
84 48
85 while ((entry = dcb_gpio_entry(dev, idx, ++i, &version))) { 49 if (!dcb_gpio_parse(nouveau_bios(gpio), idx, tag, line, func))
86 if (version < 0x40) { 50 return 0;
87 u16 data = ROM16(entry[0]);
88 *gpio = (struct gpio_func) {
89 .line = (data & 0x001f) >> 0,
90 .func = (data & 0x07e0) >> 5,
91 .log[0] = (data & 0x1800) >> 11,
92 .log[1] = (data & 0x6000) >> 13,
93 };
94 } else
95 if (version < 0x41) {
96 *gpio = (struct gpio_func) {
97 .line = entry[0] & 0x1f,
98 .func = entry[1],
99 .log[0] = (entry[3] & 0x18) >> 3,
100 .log[1] = (entry[3] & 0x60) >> 5,
101 };
102 } else {
103 *gpio = (struct gpio_func) {
104 .line = entry[0] & 0x3f,
105 .func = entry[1],
106 .log[0] = (entry[4] & 0x30) >> 4,
107 .log[1] = (entry[4] & 0xc0) >> 6,
108 };
109 }
110
111 if ((line == 0xff || line == gpio->line) &&
112 (func == 0xff || func == gpio->func))
113 return 0;
114 }
115
116 /* DCB 2.2, fixed TVDAC GPIO data */
117 if ((table = dcb_table(dev)) && table[0] >= 0x22) {
118 if (func == DCB_GPIO_TVDAC0) {
119 *gpio = (struct gpio_func) {
120 .func = DCB_GPIO_TVDAC0,
121 .line = table[-4] >> 4,
122 .log[0] = !!(table[-5] & 2),
123 .log[1] = !(table[-5] & 2),
124 };
125 return 0;
126 }
127 }
128 51
129 /* Apple iMac G4 NV18 */ 52 /* Apple iMac G4 NV18 */
130 if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) { 53 if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) {
131 if (func == DCB_GPIO_TVDAC0) { 54 if (tag == DCB_GPIO_TVDAC0) {
132 *gpio = (struct gpio_func) { 55 *func = (struct dcb_gpio_func) {
133 .func = DCB_GPIO_TVDAC0, 56 .func = DCB_GPIO_TVDAC0,
134 .line = 4, 57 .line = 4,
135 .log[0] = 0, 58 .log[0] = 0,
@@ -142,50 +65,48 @@ nouveau_gpio_find(struct drm_device *dev, int idx, u8 func, u8 line,
142 return -EINVAL; 65 return -EINVAL;
143} 66}
144 67
145int 68static int
146nouveau_gpio_set(struct drm_device *dev, int idx, u8 tag, u8 line, int state) 69nouveau_gpio_set(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, int state)
147{ 70{
148 struct gpio_func gpio; 71 struct dcb_gpio_func func;
149 int ret; 72 int ret;
150 73
151 ret = nouveau_gpio_find(dev, idx, tag, line, &gpio); 74 ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
152 if (ret == 0) { 75 if (ret == 0) {
153 int dir = !!(gpio.log[state] & 0x02); 76 int dir = !!(func.log[state] & 0x02);
154 int out = !!(gpio.log[state] & 0x01); 77 int out = !!(func.log[state] & 0x01);
155 ret = nouveau_gpio_drive(dev, idx, gpio.line, dir, out); 78 ret = nouveau_gpio_drive(gpio, idx, func.line, dir, out);
156 } 79 }
157 80
158 return ret; 81 return ret;
159} 82}
160 83
161int 84static int
162nouveau_gpio_get(struct drm_device *dev, int idx, u8 tag, u8 line) 85nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
163{ 86{
164 struct gpio_func gpio; 87 struct dcb_gpio_func func;
165 int ret; 88 int ret;
166 89
167 ret = nouveau_gpio_find(dev, idx, tag, line, &gpio); 90 ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
168 if (ret == 0) { 91 if (ret == 0) {
169 ret = nouveau_gpio_sense(dev, idx, gpio.line); 92 ret = nouveau_gpio_sense(gpio, idx, func.line);
170 if (ret >= 0) 93 if (ret >= 0)
171 ret = (ret == (gpio.log[1] & 1)); 94 ret = (ret == (func.log[1] & 1));
172 } 95 }
173 96
174 return ret; 97 return ret;
175} 98}
176 99
177int 100static int
178nouveau_gpio_irq(struct drm_device *dev, int idx, u8 tag, u8 line, bool on) 101nouveau_gpio_irq(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, bool on)
179{ 102{
180 struct drm_nouveau_private *dev_priv = dev->dev_private; 103 struct dcb_gpio_func func;
181 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
182 struct gpio_func gpio;
183 int ret; 104 int ret;
184 105
185 ret = nouveau_gpio_find(dev, idx, tag, line, &gpio); 106 ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
186 if (ret == 0) { 107 if (ret == 0) {
187 if (idx == 0 && pgpio->irq_enable) 108 if (idx == 0 && gpio->irq_enable)
188 pgpio->irq_enable(dev, gpio.line, on); 109 gpio->irq_enable(gpio, func.line, on);
189 else 110 else
190 ret = -ENODEV; 111 ret = -ENODEV;
191 } 112 }
@@ -194,11 +115,11 @@ nouveau_gpio_irq(struct drm_device *dev, int idx, u8 tag, u8 line, bool on)
194} 115}
195 116
196struct gpio_isr { 117struct gpio_isr {
197 struct drm_device *dev; 118 struct nouveau_gpio *gpio;
198 struct list_head head; 119 struct list_head head;
199 struct work_struct work; 120 struct work_struct work;
200 int idx; 121 int idx;
201 struct gpio_func func; 122 struct dcb_gpio_func func;
202 void (*handler)(void *, int); 123 void (*handler)(void *, int);
203 void *data; 124 void *data;
204 bool inhibit; 125 bool inhibit;
@@ -208,33 +129,30 @@ static void
208nouveau_gpio_isr_bh(struct work_struct *work) 129nouveau_gpio_isr_bh(struct work_struct *work)
209{ 130{
210 struct gpio_isr *isr = container_of(work, struct gpio_isr, work); 131 struct gpio_isr *isr = container_of(work, struct gpio_isr, work);
211 struct drm_device *dev = isr->dev; 132 struct nouveau_gpio *gpio = isr->gpio;
212 struct drm_nouveau_private *dev_priv = dev->dev_private;
213 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
214 unsigned long flags; 133 unsigned long flags;
215 int state; 134 int state;
216 135
217 state = nouveau_gpio_get(dev, isr->idx, isr->func.func, isr->func.line); 136 state = nouveau_gpio_get(gpio, isr->idx, isr->func.func,
137 isr->func.line);
218 if (state >= 0) 138 if (state >= 0)
219 isr->handler(isr->data, state); 139 isr->handler(isr->data, state);
220 140
221 spin_lock_irqsave(&pgpio->lock, flags); 141 spin_lock_irqsave(&gpio->lock, flags);
222 isr->inhibit = false; 142 isr->inhibit = false;
223 spin_unlock_irqrestore(&pgpio->lock, flags); 143 spin_unlock_irqrestore(&gpio->lock, flags);
224} 144}
225 145
226void 146static void
227nouveau_gpio_isr(struct drm_device *dev, int idx, u32 line_mask) 147nouveau_gpio_isr_run(struct nouveau_gpio *gpio, int idx, u32 line_mask)
228{ 148{
229 struct drm_nouveau_private *dev_priv = dev->dev_private;
230 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
231 struct gpio_isr *isr; 149 struct gpio_isr *isr;
232 150
233 if (idx != 0) 151 if (idx != 0)
234 return; 152 return;
235 153
236 spin_lock(&pgpio->lock); 154 spin_lock(&gpio->lock);
237 list_for_each_entry(isr, &pgpio->isr, head) { 155 list_for_each_entry(isr, &gpio->isr, head) {
238 if (line_mask & (1 << isr->func.line)) { 156 if (line_mask & (1 << isr->func.line)) {
239 if (isr->inhibit) 157 if (isr->inhibit)
240 continue; 158 continue;
@@ -242,15 +160,13 @@ nouveau_gpio_isr(struct drm_device *dev, int idx, u32 line_mask)
242 schedule_work(&isr->work); 160 schedule_work(&isr->work);
243 } 161 }
244 } 162 }
245 spin_unlock(&pgpio->lock); 163 spin_unlock(&gpio->lock);
246} 164}
247 165
248int 166static int
249nouveau_gpio_isr_add(struct drm_device *dev, int idx, u8 tag, u8 line, 167nouveau_gpio_isr_add(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
250 void (*handler)(void *, int), void *data) 168 void (*handler)(void *, int), void *data)
251{ 169{
252 struct drm_nouveau_private *dev_priv = dev->dev_private;
253 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
254 struct gpio_isr *isr; 170 struct gpio_isr *isr;
255 unsigned long flags; 171 unsigned long flags;
256 int ret; 172 int ret;
@@ -259,47 +175,45 @@ nouveau_gpio_isr_add(struct drm_device *dev, int idx, u8 tag, u8 line,
259 if (!isr) 175 if (!isr)
260 return -ENOMEM; 176 return -ENOMEM;
261 177
262 ret = nouveau_gpio_find(dev, idx, tag, line, &isr->func); 178 ret = nouveau_gpio_find(gpio, idx, tag, line, &isr->func);
263 if (ret) { 179 if (ret) {
264 kfree(isr); 180 kfree(isr);
265 return ret; 181 return ret;
266 } 182 }
267 183
268 INIT_WORK(&isr->work, nouveau_gpio_isr_bh); 184 INIT_WORK(&isr->work, nouveau_gpio_isr_bh);
269 isr->dev = dev; 185 isr->gpio = gpio;
270 isr->handler = handler; 186 isr->handler = handler;
271 isr->data = data; 187 isr->data = data;
272 isr->idx = idx; 188 isr->idx = idx;
273 189
274 spin_lock_irqsave(&pgpio->lock, flags); 190 spin_lock_irqsave(&gpio->lock, flags);
275 list_add(&isr->head, &pgpio->isr); 191 list_add(&isr->head, &gpio->isr);
276 spin_unlock_irqrestore(&pgpio->lock, flags); 192 spin_unlock_irqrestore(&gpio->lock, flags);
277 return 0; 193 return 0;
278} 194}
279 195
280void 196static void
281nouveau_gpio_isr_del(struct drm_device *dev, int idx, u8 tag, u8 line, 197nouveau_gpio_isr_del(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
282 void (*handler)(void *, int), void *data) 198 void (*handler)(void *, int), void *data)
283{ 199{
284 struct drm_nouveau_private *dev_priv = dev->dev_private;
285 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
286 struct gpio_isr *isr, *tmp; 200 struct gpio_isr *isr, *tmp;
287 struct gpio_func func; 201 struct dcb_gpio_func func;
288 unsigned long flags; 202 unsigned long flags;
289 LIST_HEAD(tofree); 203 LIST_HEAD(tofree);
290 int ret; 204 int ret;
291 205
292 ret = nouveau_gpio_find(dev, idx, tag, line, &func); 206 ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
293 if (ret == 0) { 207 if (ret == 0) {
294 spin_lock_irqsave(&pgpio->lock, flags); 208 spin_lock_irqsave(&gpio->lock, flags);
295 list_for_each_entry_safe(isr, tmp, &pgpio->isr, head) { 209 list_for_each_entry_safe(isr, tmp, &gpio->isr, head) {
296 if (memcmp(&isr->func, &func, sizeof(func)) || 210 if (memcmp(&isr->func, &func, sizeof(func)) ||
297 isr->idx != idx || 211 isr->idx != idx ||
298 isr->handler != handler || isr->data != data) 212 isr->handler != handler || isr->data != data)
299 continue; 213 continue;
300 list_move(&isr->head, &tofree); 214 list_move_tail(&isr->head, &tofree);
301 } 215 }
302 spin_unlock_irqrestore(&pgpio->lock, flags); 216 spin_unlock_irqrestore(&gpio->lock, flags);
303 217
304 list_for_each_entry_safe(isr, tmp, &tofree, head) { 218 list_for_each_entry_safe(isr, tmp, &tofree, head) {
305 flush_work_sync(&isr->work); 219 flush_work_sync(&isr->work);
@@ -309,92 +223,49 @@ nouveau_gpio_isr_del(struct drm_device *dev, int idx, u8 tag, u8 line,
309} 223}
310 224
311int 225int
312nouveau_gpio_create(struct drm_device *dev) 226nouveau_gpio_create_(struct nouveau_object *parent,
227 struct nouveau_object *engine,
228 struct nouveau_oclass *oclass, int length, void **pobject)
313{ 229{
314 struct drm_nouveau_private *dev_priv = dev->dev_private; 230 struct nouveau_gpio *gpio;
315 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; 231 int ret;
316 232
317 INIT_LIST_HEAD(&pgpio->isr); 233 ret = nouveau_subdev_create_(parent, engine, oclass, 0, "GPIO", "gpio",
318 spin_lock_init(&pgpio->lock); 234 length, pobject);
235 gpio = *pobject;
236 if (ret)
237 return ret;
319 238
320 return nouveau_gpio_init(dev); 239 gpio->find = nouveau_gpio_find;
240 gpio->set = nouveau_gpio_set;
241 gpio->get = nouveau_gpio_get;
242 gpio->irq = nouveau_gpio_irq;
243 gpio->isr_run = nouveau_gpio_isr_run;
244 gpio->isr_add = nouveau_gpio_isr_add;
245 gpio->isr_del = nouveau_gpio_isr_del;
246 INIT_LIST_HEAD(&gpio->isr);
247 spin_lock_init(&gpio->lock);
248 return 0;
321} 249}
322 250
323void 251static struct dmi_system_id gpio_reset_ids[] = {
324nouveau_gpio_destroy(struct drm_device *dev) 252 {
325{ 253 .ident = "Apple Macbook 10,1",
326 struct drm_nouveau_private *dev_priv = dev->dev_private; 254 .matches = {
327 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; 255 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
328 256 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
329 nouveau_gpio_fini(dev); 257 }
330 BUG_ON(!list_empty(&pgpio->isr)); 258 },
331} 259 { }
260};
332 261
333int 262int
334nouveau_gpio_init(struct drm_device *dev) 263nouveau_gpio_init(struct nouveau_gpio *gpio)
335{ 264{
336 struct drm_nouveau_private *dev_priv = dev->dev_private; 265 int ret = nouveau_subdev_init(&gpio->base);
337 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; 266 if (ret == 0 && gpio->reset) {
338 int ret = 0; 267 if (dmi_check_system(gpio_reset_ids))
339 268 gpio->reset(gpio);
340 if (pgpio->init)
341 ret = pgpio->init(dev);
342
343 return ret;
344}
345
346void
347nouveau_gpio_fini(struct drm_device *dev)
348{
349 struct drm_nouveau_private *dev_priv = dev->dev_private;
350 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
351
352 if (pgpio->fini)
353 pgpio->fini(dev);
354}
355
356void
357nouveau_gpio_reset(struct drm_device *dev)
358{
359 struct drm_nouveau_private *dev_priv = dev->dev_private;
360 u8 *entry, version;
361 int ent = -1;
362
363 while ((entry = dcb_gpio_entry(dev, 0, ++ent, &version))) {
364 u8 func = 0xff, line, defs, unk0, unk1;
365 if (version >= 0x41) {
366 defs = !!(entry[0] & 0x80);
367 line = entry[0] & 0x3f;
368 func = entry[1];
369 unk0 = entry[2];
370 unk1 = entry[3] & 0x1f;
371 } else
372 if (version >= 0x40) {
373 line = entry[0] & 0x1f;
374 func = entry[1];
375 defs = !!(entry[3] & 0x01);
376 unk0 = !!(entry[3] & 0x02);
377 unk1 = !!(entry[3] & 0x04);
378 } else {
379 break;
380 }
381
382 if (func == 0xff)
383 continue;
384
385 nouveau_gpio_func_set(dev, func, defs);
386
387 if (dev_priv->card_type >= NV_D0) {
388 nv_mask(dev, 0x00d610 + (line * 4), 0xff, unk0);
389 if (unk1--)
390 nv_mask(dev, 0x00d740 + (unk1 * 4), 0xff, line);
391 } else
392 if (dev_priv->card_type >= NV_50) {
393 static const u32 regs[] = { 0xe100, 0xe28c };
394 u32 val = (unk1 << 16) | unk0;
395 u32 reg = regs[line >> 4]; line &= 0x0f;
396
397 nv_mask(dev, reg, 0x00010001 << line, val << line);
398 }
399 } 269 }
270 return ret;
400} 271}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
index 42e600f68f2..168d16a9a8e 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
@@ -24,100 +24,146 @@
24 * 24 *
25 */ 25 */
26 26
27#include "drmP.h"
28#include "nouveau_drv.h"
29#include "nouveau_hw.h"
30#include <subdev/gpio.h> 27#include <subdev/gpio.h>
31 28
32int 29struct nv10_gpio_priv {
33nv10_gpio_sense(struct drm_device *dev, int line) 30 struct nouveau_gpio base;
31};
32
33static int
34nv10_gpio_sense(struct nouveau_gpio *gpio, int line)
34{ 35{
35 if (line < 2) { 36 if (line < 2) {
36 line = line * 16; 37 line = line * 16;
37 line = NVReadCRTC(dev, 0, NV_PCRTC_GPIO) >> line; 38 line = nv_rd32(gpio, 0x600818) >> line;
38 return !!(line & 0x0100); 39 return !!(line & 0x0100);
39 } else 40 } else
40 if (line < 10) { 41 if (line < 10) {
41 line = (line - 2) * 4; 42 line = (line - 2) * 4;
42 line = NVReadCRTC(dev, 0, NV_PCRTC_GPIO_EXT) >> line; 43 line = nv_rd32(gpio, 0x60081c) >> line;
43 return !!(line & 0x04); 44 return !!(line & 0x04);
44 } else 45 } else
45 if (line < 14) { 46 if (line < 14) {
46 line = (line - 10) * 4; 47 line = (line - 10) * 4;
47 line = NVReadCRTC(dev, 0, NV_PCRTC_850) >> line; 48 line = nv_rd32(gpio, 0x600850) >> line;
48 return !!(line & 0x04); 49 return !!(line & 0x04);
49 } 50 }
50 51
51 return -EINVAL; 52 return -EINVAL;
52} 53}
53 54
54int 55static int
55nv10_gpio_drive(struct drm_device *dev, int line, int dir, int out) 56nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
56{ 57{
57 u32 reg, mask, data; 58 u32 reg, mask, data;
58 59
59 if (line < 2) { 60 if (line < 2) {
60 line = line * 16; 61 line = line * 16;
61 reg = NV_PCRTC_GPIO; 62 reg = 0x600818;
62 mask = 0x00000011; 63 mask = 0x00000011;
63 data = (dir << 4) | out; 64 data = (dir << 4) | out;
64 } else 65 } else
65 if (line < 10) { 66 if (line < 10) {
66 line = (line - 2) * 4; 67 line = (line - 2) * 4;
67 reg = NV_PCRTC_GPIO_EXT; 68 reg = 0x60081c;
68 mask = 0x00000003; 69 mask = 0x00000003;
69 data = (dir << 1) | out; 70 data = (dir << 1) | out;
70 } else 71 } else
71 if (line < 14) { 72 if (line < 14) {
72 line = (line - 10) * 4; 73 line = (line - 10) * 4;
73 reg = NV_PCRTC_850; 74 reg = 0x600850;
74 mask = 0x00000003; 75 mask = 0x00000003;
75 data = (dir << 1) | out; 76 data = (dir << 1) | out;
76 } else { 77 } else {
77 return -EINVAL; 78 return -EINVAL;
78 } 79 }
79 80
80 mask = NVReadCRTC(dev, 0, reg) & ~(mask << line); 81 nv_mask(gpio, reg, mask << line, data << line);
81 NVWriteCRTC(dev, 0, reg, mask | (data << line));
82 return 0; 82 return 0;
83} 83}
84 84
85void 85static void
86nv10_gpio_irq_enable(struct drm_device *dev, int line, bool on) 86nv10_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on)
87{ 87{
88 u32 mask = 0x00010001 << line; 88 u32 mask = 0x00010001 << line;
89 89
90 nv_wr32(dev, 0x001104, mask); 90 nv_wr32(gpio, 0x001104, mask);
91 nv_mask(dev, 0x001144, mask, on ? mask : 0); 91 nv_mask(gpio, 0x001144, mask, on ? mask : 0);
92} 92}
93 93
94static void 94static void
95nv10_gpio_isr(struct drm_device *dev) 95nv10_gpio_intr(struct nouveau_subdev *subdev)
96{ 96{
97 u32 intr = nv_rd32(dev, 0x1104); 97 struct nv10_gpio_priv *priv = (void *)subdev;
98 u32 intr = nv_rd32(priv, 0x001104);
98 u32 hi = (intr & 0x0000ffff) >> 0; 99 u32 hi = (intr & 0x0000ffff) >> 0;
99 u32 lo = (intr & 0xffff0000) >> 16; 100 u32 lo = (intr & 0xffff0000) >> 16;
100 101
101 nouveau_gpio_isr(dev, 0, hi | lo); 102 priv->base.isr_run(&priv->base, 0, hi | lo);
102 103
103 nv_wr32(dev, 0x001104, intr); 104 nv_wr32(priv, 0x001104, intr);
104} 105}
105 106
106int 107static int
107nv10_gpio_init(struct drm_device *dev) 108nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
109 struct nouveau_oclass *oclass, void *data, u32 size,
110 struct nouveau_object **pobject)
108{ 111{
109 nv_wr32(dev, 0x001140, 0x00000000); 112 struct nv10_gpio_priv *priv;
110 nv_wr32(dev, 0x001100, 0xffffffff); 113 int ret;
111 nv_wr32(dev, 0x001144, 0x00000000); 114
112 nv_wr32(dev, 0x001104, 0xffffffff); 115 ret = nouveau_gpio_create(parent, engine, oclass, &priv);
113 nouveau_irq_register(dev, 28, nv10_gpio_isr); /* PBUS */ 116 *pobject = nv_object(priv);
117 if (ret)
118 return ret;
119
120 priv->base.drive = nv10_gpio_drive;
121 priv->base.sense = nv10_gpio_sense;
122 priv->base.irq_enable = nv10_gpio_irq_enable;
123 nv_subdev(priv)->intr = nv10_gpio_intr;
114 return 0; 124 return 0;
115} 125}
116 126
117void 127static void
118nv10_gpio_fini(struct drm_device *dev) 128nv10_gpio_dtor(struct nouveau_object *object)
119{ 129{
120 nv_wr32(dev, 0x001140, 0x00000000); 130 struct nv10_gpio_priv *priv = (void *)object;
121 nv_wr32(dev, 0x001144, 0x00000000); 131 nouveau_gpio_destroy(&priv->base);
122 nouveau_irq_unregister(dev, 28);
123} 132}
133
134static int
135nv10_gpio_init(struct nouveau_object *object)
136{
137 struct nv10_gpio_priv *priv = (void *)object;
138 int ret;
139
140 ret = nouveau_gpio_init(&priv->base);
141 if (ret)
142 return ret;
143
144 nv_wr32(priv, 0x001140, 0x00000000);
145 nv_wr32(priv, 0x001100, 0xffffffff);
146 nv_wr32(priv, 0x001144, 0x00000000);
147 nv_wr32(priv, 0x001104, 0xffffffff);
148 return 0;
149}
150
151static int
152nv10_gpio_fini(struct nouveau_object *object, bool suspend)
153{
154 struct nv10_gpio_priv *priv = (void *)object;
155 nv_wr32(priv, 0x001140, 0x00000000);
156 nv_wr32(priv, 0x001144, 0x00000000);
157 return nouveau_gpio_fini(&priv->base, suspend);
158}
159
160struct nouveau_oclass
161nv10_gpio_oclass = {
162 .handle = NV_SUBDEV(GPIO, 0x10),
163 .ofuncs = &(struct nouveau_ofuncs) {
164 .ctor = nv10_gpio_ctor,
165 .dtor = nv10_gpio_dtor,
166 .init = nv10_gpio_init,
167 .fini = nv10_gpio_fini,
168 },
169};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
index 48509b0a1c8..f3502c961cd 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright 2010 Red Hat Inc. 2 * Copyright 2012 Red Hat Inc.
3 * 3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a 4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"), 5 * copy of this software and associated documentation files (the "Software"),
@@ -22,18 +22,45 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24 24
25#include <linux/dmi.h>
26#include "drmP.h"
27#include "nouveau_drv.h"
28#include "nouveau_hw.h"
29#include <subdev/gpio.h> 25#include <subdev/gpio.h>
30 26
31#include "nv50_display.h" 27struct nv50_gpio_priv {
28 struct nouveau_gpio base;
29};
30
31static void
32nv50_gpio_reset(struct nouveau_gpio *gpio)
33{
34 struct nouveau_bios *bios = nouveau_bios(gpio);
35 struct nv50_gpio_priv *priv = (void *)gpio;
36 u16 entry;
37 u8 ver;
38 int ent = -1;
39
40 while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) {
41 static const u32 regs[] = { 0xe100, 0xe28c };
42 u32 data = nv_ro32(bios, entry);
43 u8 line = (data & 0x0000001f);
44 u8 func = (data & 0x0000ff00) >> 8;
45 u8 defs = !!(data & 0x01000000);
46 u8 unk0 = !!(data & 0x02000000);
47 u8 unk1 = !!(data & 0x04000000);
48 u32 val = (unk1 << 16) | unk0;
49 u32 reg = regs[line >> 4]; line &= 0x0f;
50
51 if (func == 0xff)
52 continue;
53
54 gpio->set(gpio, 0, func, line, defs);
55
56 nv_mask(priv, reg, 0x00010001 << line, val << line);
57 }
58}
32 59
33static int 60static int
34nv50_gpio_location(int line, u32 *reg, u32 *shift) 61nv50_gpio_location(int line, u32 *reg, u32 *shift)
35{ 62{
36 const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; 63 const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
37 64
38 if (line >= 32) 65 if (line >= 32)
39 return -EINVAL; 66 return -EINVAL;
@@ -43,113 +70,125 @@ nv50_gpio_location(int line, u32 *reg, u32 *shift)
43 return 0; 70 return 0;
44} 71}
45 72
46int 73static int
47nv50_gpio_drive(struct drm_device *dev, int line, int dir, int out) 74nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
48{ 75{
49 u32 reg, shift; 76 u32 reg, shift;
50 77
51 if (nv50_gpio_location(line, &reg, &shift)) 78 if (nv50_gpio_location(line, &reg, &shift))
52 return -EINVAL; 79 return -EINVAL;
53 80
54 nv_mask(dev, reg, 7 << shift, (((dir ^ 1) << 1) | out) << shift); 81 nv_mask(gpio, reg, 7 << shift, (((dir ^ 1) << 1) | out) << shift);
55 return 0; 82 return 0;
56} 83}
57 84
58int 85static int
59nv50_gpio_sense(struct drm_device *dev, int line) 86nv50_gpio_sense(struct nouveau_gpio *gpio, int line)
60{ 87{
61 u32 reg, shift; 88 u32 reg, shift;
62 89
63 if (nv50_gpio_location(line, &reg, &shift)) 90 if (nv50_gpio_location(line, &reg, &shift))
64 return -EINVAL; 91 return -EINVAL;
65 92
66 return !!(nv_rd32(dev, reg) & (4 << shift)); 93 return !!(nv_rd32(gpio, reg) & (4 << shift));
67} 94}
68 95
69void 96void
70nv50_gpio_irq_enable(struct drm_device *dev, int line, bool on) 97nv50_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on)
71{ 98{
72 u32 reg = line < 16 ? 0xe050 : 0xe070; 99 u32 reg = line < 16 ? 0xe050 : 0xe070;
73 u32 mask = 0x00010001 << (line & 0xf); 100 u32 mask = 0x00010001 << (line & 0xf);
74 101
75 nv_wr32(dev, reg + 4, mask); 102 nv_wr32(gpio, reg + 4, mask);
76 nv_mask(dev, reg + 0, mask, on ? mask : 0); 103 nv_mask(gpio, reg + 0, mask, on ? mask : 0);
77}
78
79int
80nvd0_gpio_drive(struct drm_device *dev, int line, int dir, int out)
81{
82 u32 data = ((dir ^ 1) << 13) | (out << 12);
83 nv_mask(dev, 0x00d610 + (line * 4), 0x00003000, data);
84 nv_mask(dev, 0x00d604, 0x00000001, 0x00000001); /* update? */
85 return 0;
86}
87
88int
89nvd0_gpio_sense(struct drm_device *dev, int line)
90{
91 return !!(nv_rd32(dev, 0x00d610 + (line * 4)) & 0x00004000);
92} 104}
93 105
94static void 106void
95nv50_gpio_isr(struct drm_device *dev) 107nv50_gpio_intr(struct nouveau_subdev *subdev)
96{ 108{
97 struct drm_nouveau_private *dev_priv = dev->dev_private; 109 struct nv50_gpio_priv *priv = (void *)subdev;
98 u32 intr0, intr1 = 0; 110 u32 intr0, intr1 = 0;
99 u32 hi, lo; 111 u32 hi, lo;
100 112
101 intr0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050); 113 intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
102 if (dev_priv->chipset >= 0x90) 114 if (nv_device(priv)->chipset >= 0x90)
103 intr1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070); 115 intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);
104 116
105 hi = (intr0 & 0x0000ffff) | (intr1 << 16); 117 hi = (intr0 & 0x0000ffff) | (intr1 << 16);
106 lo = (intr0 >> 16) | (intr1 & 0xffff0000); 118 lo = (intr0 >> 16) | (intr1 & 0xffff0000);
107 nouveau_gpio_isr(dev, 0, hi | lo); 119 priv->base.isr_run(&priv->base, 0, hi | lo);
108 120
109 nv_wr32(dev, 0xe054, intr0); 121 nv_wr32(priv, 0xe054, intr0);
110 if (dev_priv->chipset >= 0x90) 122 if (nv_device(priv)->chipset >= 0x90)
111 nv_wr32(dev, 0xe074, intr1); 123 nv_wr32(priv, 0xe074, intr1);
112} 124}
113 125
114static struct dmi_system_id gpio_reset_ids[] = { 126static int
115 { 127nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
116 .ident = "Apple Macbook 10,1", 128 struct nouveau_oclass *oclass, void *data, u32 size,
117 .matches = { 129 struct nouveau_object **pobject)
118 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 130{
119 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"), 131 struct nv50_gpio_priv *priv;
120 } 132 int ret;
121 }, 133
122 { } 134 ret = nouveau_gpio_create(parent, engine, oclass, &priv);
123}; 135 *pobject = nv_object(priv);
136 if (ret)
137 return ret;
138
139 priv->base.reset = nv50_gpio_reset;
140 priv->base.drive = nv50_gpio_drive;
141 priv->base.sense = nv50_gpio_sense;
142 priv->base.irq_enable = nv50_gpio_irq_enable;
143 nv_subdev(priv)->intr = nv50_gpio_intr;
144 return 0;
145}
146
147void
148nv50_gpio_dtor(struct nouveau_object *object)
149{
150 struct nv50_gpio_priv *priv = (void *)object;
151 nouveau_gpio_destroy(&priv->base);
152}
124 153
125int 154int
126nv50_gpio_init(struct drm_device *dev) 155nv50_gpio_init(struct nouveau_object *object)
127{ 156{
128 struct drm_nouveau_private *dev_priv = dev->dev_private; 157 struct nv50_gpio_priv *priv = (void *)object;
158 int ret;
129 159
130 /* initialise gpios and routing to vbios defaults */ 160 ret = nouveau_gpio_init(&priv->base);
131 if (dmi_check_system(gpio_reset_ids)) 161 if (ret)
132 nouveau_gpio_reset(dev); 162 return ret;
133 163
134 /* disable, and ack any pending gpio interrupts */ 164 /* disable, and ack any pending gpio interrupts */
135 nv_wr32(dev, 0xe050, 0x00000000); 165 nv_wr32(priv, 0xe050, 0x00000000);
136 nv_wr32(dev, 0xe054, 0xffffffff); 166 nv_wr32(priv, 0xe054, 0xffffffff);
137 if (dev_priv->chipset >= 0x90) { 167 if (nv_device(priv)->chipset >= 0x90) {
138 nv_wr32(dev, 0xe070, 0x00000000); 168 nv_wr32(priv, 0xe070, 0x00000000);
139 nv_wr32(dev, 0xe074, 0xffffffff); 169 nv_wr32(priv, 0xe074, 0xffffffff);
140 } 170 }
141 171
142 nouveau_irq_register(dev, 21, nv50_gpio_isr);
143 return 0; 172 return 0;
144} 173}
145 174
146void 175int
147nv50_gpio_fini(struct drm_device *dev) 176nv50_gpio_fini(struct nouveau_object *object, bool suspend)
148{ 177{
149 struct drm_nouveau_private *dev_priv = dev->dev_private; 178 struct nv50_gpio_priv *priv = (void *)object;
150 179 nv_wr32(priv, 0xe050, 0x00000000);
151 nv_wr32(dev, 0xe050, 0x00000000); 180 if (nv_device(priv)->chipset >= 0x90)
152 if (dev_priv->chipset >= 0x90) 181 nv_wr32(priv, 0xe070, 0x00000000);
153 nv_wr32(dev, 0xe070, 0x00000000); 182 return nouveau_gpio_fini(&priv->base, suspend);
154 nouveau_irq_unregister(dev, 21);
155} 183}
184
185struct nouveau_oclass
186nv50_gpio_oclass = {
187 .handle = NV_SUBDEV(GPIO, 0x50),
188 .ofuncs = &(struct nouveau_ofuncs) {
189 .ctor = nv50_gpio_ctor,
190 .dtor = nv50_gpio_dtor,
191 .init = nv50_gpio_init,
192 .fini = nv50_gpio_fini,
193 },
194};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
new file mode 100644
index 00000000000..8d18fcad26e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
@@ -0,0 +1,104 @@
1/*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
25#include <subdev/gpio.h>
26
27struct nvd0_gpio_priv {
28 struct nouveau_gpio base;
29};
30
31static void
32nvd0_gpio_reset(struct nouveau_gpio *gpio)
33{
34 struct nouveau_bios *bios = nouveau_bios(gpio);
35 struct nvd0_gpio_priv *priv = (void *)gpio;
36 u16 entry;
37 u8 ver;
38 int ent = -1;
39
40 while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) {
41 u32 data = nv_ro32(bios, entry);
42 u8 line = (data & 0x0000003f);
43 u8 defs = !!(data & 0x00000080);
44 u8 func = (data & 0x0000ff00) >> 8;
45 u8 unk0 = (data & 0x00ff0000) >> 16;
46 u8 unk1 = (data & 0x1f000000) >> 24;
47
48 if (func == 0xff)
49 continue;
50
51 gpio->set(gpio, 0, func, line, defs);
52
53 nv_mask(priv, 0x00d610 + (line * 4), 0xff, unk0);
54 if (unk1--)
55 nv_mask(priv, 0x00d740 + (unk1 * 4), 0xff, line);
56 }
57}
58
59static int
60nvd0_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
61{
62 u32 data = ((dir ^ 1) << 13) | (out << 12);
63 nv_mask(gpio, 0x00d610 + (line * 4), 0x00003000, data);
64 nv_mask(gpio, 0x00d604, 0x00000001, 0x00000001); /* update? */
65 return 0;
66}
67
68static int
69nvd0_gpio_sense(struct nouveau_gpio *gpio, int line)
70{
71 return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000);
72}
73
74static int
75nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
76 struct nouveau_oclass *oclass, void *data, u32 size,
77 struct nouveau_object **pobject)
78{
79 struct nvd0_gpio_priv *priv;
80 int ret;
81
82 ret = nouveau_gpio_create(parent, engine, oclass, &priv);
83 *pobject = nv_object(priv);
84 if (ret)
85 return ret;
86
87 priv->base.reset = nvd0_gpio_reset;
88 priv->base.drive = nvd0_gpio_drive;
89 priv->base.sense = nvd0_gpio_sense;
90 priv->base.irq_enable = nv50_gpio_irq_enable;
91 nv_subdev(priv)->intr = nv50_gpio_intr;
92 return 0;
93}
94
95struct nouveau_oclass
96nvd0_gpio_oclass = {
97 .handle = NV_SUBDEV(GPIO, 0xd0),
98 .ofuncs = &(struct nouveau_ofuncs) {
99 .ctor = nvd0_gpio_ctor,
100 .dtor = nv50_gpio_dtor,
101 .init = nv50_gpio_init,
102 .fini = nv50_gpio_fini,
103 },
104};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
index 71e93615834..740e399bc7a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
@@ -118,7 +118,7 @@ static const uint32_t nv50_i2c_port[] = {
118static u8 * 118static u8 *
119i2c_table(struct drm_device *dev, u8 *version) 119i2c_table(struct drm_device *dev, u8 *version)
120{ 120{
121 u8 *dcb = dcb_table(dev), *i2c = NULL; 121 u8 *dcb = olddcb_table(dev), *i2c = NULL;
122 if (dcb) { 122 if (dcb) {
123 if (dcb[0] >= 0x15) 123 if (dcb[0] >= 0x15)
124 i2c = ROMPTR(dev, dcb[2]); 124 i2c = ROMPTR(dev, dcb[2]);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index f86985363ac..4f0d9bd1914 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -27,7 +27,6 @@
27#include "nouveau_drv.h" 27#include "nouveau_drv.h"
28#include "nouveau_hw.h" 28#include "nouveau_hw.h"
29#include "nouveau_encoder.h" 29#include "nouveau_encoder.h"
30#include <subdev/gpio.h>
31 30
32#include <linux/io-mapping.h> 31#include <linux/io-mapping.h>
33#include <linux/firmware.h> 32#include <linux/firmware.h>
@@ -5384,7 +5383,7 @@ static uint16_t findstr(uint8_t *data, int n, const uint8_t *str, int len)
5384} 5383}
5385 5384
5386void * 5385void *
5387dcb_table(struct drm_device *dev) 5386olddcb_table(struct drm_device *dev)
5388{ 5387{
5389 struct drm_nouveau_private *dev_priv = dev->dev_private; 5388 struct drm_nouveau_private *dev_priv = dev->dev_private;
5390 u8 *dcb = NULL; 5389 u8 *dcb = NULL;
@@ -5438,9 +5437,9 @@ dcb_table(struct drm_device *dev)
5438} 5437}
5439 5438
5440void * 5439void *
5441dcb_outp(struct drm_device *dev, u8 idx) 5440olddcb_outp(struct drm_device *dev, u8 idx)
5442{ 5441{
5443 u8 *dcb = dcb_table(dev); 5442 u8 *dcb = olddcb_table(dev);
5444 if (dcb && dcb[0] >= 0x30) { 5443 if (dcb && dcb[0] >= 0x30) {
5445 if (idx < dcb[2]) 5444 if (idx < dcb[2])
5446 return dcb + dcb[1] + (idx * dcb[3]); 5445 return dcb + dcb[1] + (idx * dcb[3]);
@@ -5462,12 +5461,12 @@ dcb_outp(struct drm_device *dev, u8 idx)
5462} 5461}
5463 5462
5464int 5463int
5465dcb_outp_foreach(struct drm_device *dev, void *data, 5464olddcb_outp_foreach(struct drm_device *dev, void *data,
5466 int (*exec)(struct drm_device *, void *, int idx, u8 *outp)) 5465 int (*exec)(struct drm_device *, void *, int idx, u8 *outp))
5467{ 5466{
5468 int ret, idx = -1; 5467 int ret, idx = -1;
5469 u8 *outp = NULL; 5468 u8 *outp = NULL;
5470 while ((outp = dcb_outp(dev, ++idx))) { 5469 while ((outp = olddcb_outp(dev, ++idx))) {
5471 if (ROM32(outp[0]) == 0x00000000) 5470 if (ROM32(outp[0]) == 0x00000000)
5472 break; /* seen on an NV11 with DCB v1.5 */ 5471 break; /* seen on an NV11 with DCB v1.5 */
5473 if (ROM32(outp[0]) == 0xffffffff) 5472 if (ROM32(outp[0]) == 0xffffffff)
@@ -5489,7 +5488,7 @@ dcb_outp_foreach(struct drm_device *dev, void *data,
5489u8 * 5488u8 *
5490dcb_conntab(struct drm_device *dev) 5489dcb_conntab(struct drm_device *dev)
5491{ 5490{
5492 u8 *dcb = dcb_table(dev); 5491 u8 *dcb = olddcb_table(dev);
5493 if (dcb && dcb[0] >= 0x30 && dcb[1] >= 0x16) { 5492 if (dcb && dcb[0] >= 0x30 && dcb[1] >= 0x16) {
5494 u8 *conntab = ROMPTR(dev, dcb[0x14]); 5493 u8 *conntab = ROMPTR(dev, dcb[0x14]);
5495 if (conntab && conntab[0] >= 0x30 && conntab[0] <= 0x40) 5494 if (conntab && conntab[0] >= 0x30 && conntab[0] <= 0x40)
@@ -5982,7 +5981,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
5982 u8 *dcbt, *conn; 5981 u8 *dcbt, *conn;
5983 int idx; 5982 int idx;
5984 5983
5985 dcbt = dcb_table(dev); 5984 dcbt = olddcb_table(dev);
5986 if (!dcbt) { 5985 if (!dcbt) {
5987 /* handle pre-DCB boards */ 5986 /* handle pre-DCB boards */
5988 if (bios->type == NVBIOS_BMP) { 5987 if (bios->type == NVBIOS_BMP) {
@@ -5996,7 +5995,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
5996 NV_TRACE(dev, "DCB version %d.%d\n", dcbt[0] >> 4, dcbt[0] & 0xf); 5995 NV_TRACE(dev, "DCB version %d.%d\n", dcbt[0] >> 4, dcbt[0] & 0xf);
5997 5996
5998 dcb->version = dcbt[0]; 5997 dcb->version = dcbt[0];
5999 dcb_outp_foreach(dev, NULL, parse_dcb_entry); 5998 olddcb_outp_foreach(dev, NULL, parse_dcb_entry);
6000 5999
6001 /* 6000 /*
6002 * apart for v2.1+ not being known for requiring merging, this 6001 * apart for v2.1+ not being known for requiring merging, this
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index b42aa31144a..b4529a0b35a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -53,15 +53,6 @@ struct bit_entry {
53 53
54int bit_table(struct drm_device *, u8 id, struct bit_entry *); 54int bit_table(struct drm_device *, u8 id, struct bit_entry *);
55 55
56enum dcb_gpio_tag {
57 DCB_GPIO_PANEL_POWER = 0x01,
58 DCB_GPIO_TVDAC0 = 0x0c,
59 DCB_GPIO_TVDAC1 = 0x2d,
60 DCB_GPIO_PWM_FAN = 0x09,
61 DCB_GPIO_FAN_SENSE = 0x3d,
62 DCB_GPIO_UNUSED = 0xff
63};
64
65enum dcb_connector_type { 56enum dcb_connector_type {
66 DCB_CONNECTOR_VGA = 0x00, 57 DCB_CONNECTOR_VGA = 0x00,
67 DCB_CONNECTOR_TV_0 = 0x10, 58 DCB_CONNECTOR_TV_0 = 0x10,
@@ -302,9 +293,9 @@ struct nvbios {
302 } legacy; 293 } legacy;
303}; 294};
304 295
305void *dcb_table(struct drm_device *); 296void *olddcb_table(struct drm_device *);
306void *dcb_outp(struct drm_device *, u8 idx); 297void *olddcb_outp(struct drm_device *, u8 idx);
307int dcb_outp_foreach(struct drm_device *, void *data, 298int olddcb_outp_foreach(struct drm_device *, void *data,
308 int (*)(struct drm_device *, void *, int idx, u8 *outp)); 299 int (*)(struct drm_device *, void *, int idx, u8 *outp));
309u8 *dcb_conntab(struct drm_device *); 300u8 *dcb_conntab(struct drm_device *);
310u8 *dcb_conn(struct drm_device *, u8 idx); 301u8 *dcb_conn(struct drm_device *, u8 idx);
diff --git a/drivers/gpu/drm/nouveau/nouveau_compat.c b/drivers/gpu/drm/nouveau/nouveau_compat.c
index ca871d66f28..81fc8494e76 100644
--- a/drivers/gpu/drm/nouveau/nouveau_compat.c
+++ b/drivers/gpu/drm/nouveau/nouveau_compat.c
@@ -2,6 +2,7 @@
2#include "nouveau_compat.h" 2#include "nouveau_compat.h"
3 3
4#include <subdev/bios.h> 4#include <subdev/bios.h>
5#include <subdev/gpio.h>
5 6
6void *nouveau_newpriv(struct drm_device *); 7void *nouveau_newpriv(struct drm_device *);
7 8
@@ -50,3 +51,82 @@ _nv_bios(struct drm_device *dev, u8 **data, u32 *size)
50 *size = bios->size; 51 *size = bios->size;
51 return true; 52 return true;
52} 53}
54
55void
56nouveau_gpio_reset(struct drm_device *dev)
57{
58 struct nouveau_drm *drm = nouveau_newpriv(dev);
59 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
60 gpio->reset(gpio);
61}
62
63int
64nouveau_gpio_find(struct drm_device *dev, int idx, u8 tag, u8 line,
65 struct dcb_gpio_func *func)
66{
67 struct nouveau_drm *drm = nouveau_newpriv(dev);
68 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
69
70 return gpio->find(gpio, idx, tag, line, func);
71}
72
73bool
74nouveau_gpio_func_valid(struct drm_device *dev, u8 tag)
75{
76 struct nouveau_drm *drm = nouveau_newpriv(dev);
77 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
78 struct dcb_gpio_func func;
79
80 return gpio->find(gpio, 0, tag, 0xff, &func) == 0;
81}
82
83int
84nouveau_gpio_func_set(struct drm_device *dev, u8 tag, int state)
85{
86 struct nouveau_drm *drm = nouveau_newpriv(dev);
87 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
88 if (gpio && gpio->get)
89 return gpio->set(gpio, 0, tag, 0xff, state);
90 return -ENODEV;
91}
92
93int
94nouveau_gpio_func_get(struct drm_device *dev, u8 tag)
95{
96 struct nouveau_drm *drm = nouveau_newpriv(dev);
97 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
98 if (gpio && gpio->get)
99 return gpio->get(gpio, 0, tag, 0xff);
100 return -ENODEV;
101}
102
103int
104nouveau_gpio_irq(struct drm_device *dev, int idx, u8 tag, u8 line, bool on)
105{
106 struct nouveau_drm *drm = nouveau_newpriv(dev);
107 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
108 if (gpio && gpio->irq)
109 return gpio->irq(gpio, idx, tag, line, on);
110 return -ENODEV;
111}
112
113int
114nouveau_gpio_isr_add(struct drm_device *dev, int idx, u8 tag, u8 line,
115 void (*exec)(void *, int state), void *data)
116{
117 struct nouveau_drm *drm = nouveau_newpriv(dev);
118 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
119 if (gpio && gpio->isr_add)
120 return gpio->isr_add(gpio, idx, tag, line, exec, data);
121 return -ENODEV;
122}
123
124void
125nouveau_gpio_isr_del(struct drm_device *dev, int idx, u8 tag, u8 line,
126 void (*exec)(void *, int state), void *data)
127{
128 struct nouveau_drm *drm = nouveau_newpriv(dev);
129 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
130 if (gpio && gpio->isr_del)
131 gpio->isr_del(gpio, idx, tag, line, exec, data);
132}
diff --git a/drivers/gpu/drm/nouveau/nouveau_compat.h b/drivers/gpu/drm/nouveau/nouveau_compat.h
index d1ce3bc7793..f1143c362db 100644
--- a/drivers/gpu/drm/nouveau/nouveau_compat.h
+++ b/drivers/gpu/drm/nouveau/nouveau_compat.h
@@ -9,4 +9,15 @@ u32 _nv_mask(struct drm_device *, u32, u32, u32);
9 9
10bool _nv_bios(struct drm_device *, u8 **, u32 *); 10bool _nv_bios(struct drm_device *, u8 **, u32 *);
11 11
12struct dcb_gpio_func;
13void nouveau_gpio_reset(struct drm_device *);
14int nouveau_gpio_find(struct drm_device *, int, u8, u8, struct dcb_gpio_func *);
15bool nouveau_gpio_func_valid(struct drm_device *, u8 tag);
16int nouveau_gpio_func_set(struct drm_device *, u8 tag, int state);
17int nouveau_gpio_func_get(struct drm_device *, u8 tag);
18int nouveau_gpio_irq(struct drm_device *, int idx, u8 tag, u8 line, bool on);
19int nouveau_gpio_isr_add(struct drm_device *, int idx, u8 tag, u8 line,
20 void (*)(void *, int state), void *data);
21void nouveau_gpio_isr_del(struct drm_device *, int idx, u8 tag, u8 line,
22 void (*)(void *, int state), void *data);
12#endif 23#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index d6eabd98506..cbf8348ca22 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -35,9 +35,10 @@
35#include "nouveau_encoder.h" 35#include "nouveau_encoder.h"
36#include "nouveau_crtc.h" 36#include "nouveau_crtc.h"
37#include "nouveau_connector.h" 37#include "nouveau_connector.h"
38#include <subdev/gpio.h>
39#include "nouveau_hw.h" 38#include "nouveau_hw.h"
40 39
40#include <subdev/bios/gpio.h>
41
41static void nouveau_connector_hotplug(void *, int); 42static void nouveau_connector_hotplug(void *, int);
42 43
43struct nouveau_encoder * 44struct nouveau_encoder *
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index d6051e01967..44835c46495 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -34,10 +34,11 @@
34#include "nouveau_dma.h" 34#include "nouveau_dma.h"
35#include "nouveau_connector.h" 35#include "nouveau_connector.h"
36#include "nouveau_software.h" 36#include "nouveau_software.h"
37#include <subdev/gpio.h>
38#include "nouveau_fence.h" 37#include "nouveau_fence.h"
39#include "nv50_display.h" 38#include "nv50_display.h"
40 39
40#include <subdev/bios/gpio.h>
41
41static void 42static void
42nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) 43nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
43{ 44{
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 67b322554ac..63c0e827c30 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -29,7 +29,6 @@
29#include "nouveau_connector.h" 29#include "nouveau_connector.h"
30#include "nouveau_encoder.h" 30#include "nouveau_encoder.h"
31#include "nouveau_crtc.h" 31#include "nouveau_crtc.h"
32#include <subdev/gpio.h>
33 32
34/****************************************************************************** 33/******************************************************************************
35 * aux channel util functions 34 * aux channel util functions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 581a95078a3..afe97870209 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -366,16 +366,6 @@ struct nouveau_display_engine {
366 struct drm_property *color_vibrance_property; 366 struct drm_property *color_vibrance_property;
367}; 367};
368 368
369struct nouveau_gpio_engine {
370 spinlock_t lock;
371 struct list_head isr;
372 int (*init)(struct drm_device *);
373 void (*fini)(struct drm_device *);
374 int (*drive)(struct drm_device *, int line, int dir, int out);
375 int (*sense)(struct drm_device *, int line);
376 void (*irq_enable)(struct drm_device *, int line, bool);
377};
378
379struct nouveau_pm_voltage_level { 369struct nouveau_pm_voltage_level {
380 u32 voltage; /* microvolts */ 370 u32 voltage; /* microvolts */
381 u8 vid; 371 u8 vid;
@@ -555,7 +545,6 @@ struct nouveau_engine {
555 struct nouveau_timer_engine timer; 545 struct nouveau_timer_engine timer;
556 struct nouveau_fb_engine fb; 546 struct nouveau_fb_engine fb;
557 struct nouveau_display_engine display; 547 struct nouveau_display_engine display;
558 struct nouveau_gpio_engine gpio;
559 struct nouveau_pm_engine pm; 548 struct nouveau_pm_engine pm;
560 struct nouveau_vram_engine vram; 549 struct nouveau_vram_engine vram;
561}; 550};
@@ -1376,22 +1365,6 @@ int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *,
1376int nouveau_display_dumb_destroy(struct drm_file *, struct drm_device *, 1365int nouveau_display_dumb_destroy(struct drm_file *, struct drm_device *,
1377 uint32_t handle); 1366 uint32_t handle);
1378 1367
1379/* nv10_gpio.c */
1380int nv10_gpio_init(struct drm_device *dev);
1381void nv10_gpio_fini(struct drm_device *dev);
1382int nv10_gpio_drive(struct drm_device *dev, int line, int dir, int out);
1383int nv10_gpio_sense(struct drm_device *dev, int line);
1384void nv10_gpio_irq_enable(struct drm_device *, int line, bool on);
1385
1386/* nv50_gpio.c */
1387int nv50_gpio_init(struct drm_device *dev);
1388void nv50_gpio_fini(struct drm_device *dev);
1389int nv50_gpio_drive(struct drm_device *dev, int line, int dir, int out);
1390int nv50_gpio_sense(struct drm_device *dev, int line);
1391void nv50_gpio_irq_enable(struct drm_device *, int line, bool on);
1392int nvd0_gpio_drive(struct drm_device *dev, int line, int dir, int out);
1393int nvd0_gpio_sense(struct drm_device *dev, int line);
1394
1395/* nv50_calc.c */ 1368/* nv50_calc.c */
1396int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk, 1369int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
1397 int *N1, int *M1, int *N2, int *M2, int *P); 1370 int *N1, int *M1, int *N2, int *M2, int *P);
diff --git a/drivers/gpu/drm/nouveau/nouveau_mxm.c b/drivers/gpu/drm/nouveau/nouveau_mxm.c
index 07d0d1e0369..b2b326b83ed 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mxm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mxm.c
@@ -460,13 +460,13 @@ mxm_show_unmatched(struct drm_device *dev, u8 *data, void *info)
460static void 460static void
461mxm_dcb_sanitise(struct drm_device *dev) 461mxm_dcb_sanitise(struct drm_device *dev)
462{ 462{
463 u8 *dcb = dcb_table(dev); 463 u8 *dcb = olddcb_table(dev);
464 if (!dcb || dcb[0] != 0x40) { 464 if (!dcb || dcb[0] != 0x40) {
465 MXM_DBG(dev, "unsupported DCB version\n"); 465 MXM_DBG(dev, "unsupported DCB version\n");
466 return; 466 return;
467 } 467 }
468 468
469 dcb_outp_foreach(dev, NULL, mxm_dcb_sanitise_entry); 469 olddcb_outp_foreach(dev, NULL, mxm_dcb_sanitise_entry);
470 mxms_foreach(dev, 0x01, mxm_show_unmatched, NULL); 470 mxms_foreach(dev, 0x01, mxm_show_unmatched, NULL);
471} 471}
472 472
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index dc34664572c..fd74cbf7ef6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -26,7 +26,7 @@
26 26
27#include "nouveau_drv.h" 27#include "nouveau_drv.h"
28#include "nouveau_pm.h" 28#include "nouveau_pm.h"
29#include <subdev/gpio.h> 29#include <subdev/bios/gpio.h>
30 30
31#ifdef CONFIG_ACPI 31#ifdef CONFIG_ACPI
32#include <linux/acpi.h> 32#include <linux/acpi.h>
@@ -40,7 +40,7 @@ nouveau_pwmfan_get(struct drm_device *dev)
40{ 40{
41 struct drm_nouveau_private *dev_priv = dev->dev_private; 41 struct drm_nouveau_private *dev_priv = dev->dev_private;
42 struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 42 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
43 struct gpio_func gpio; 43 struct dcb_gpio_func gpio;
44 u32 divs, duty; 44 u32 divs, duty;
45 int ret; 45 int ret;
46 46
@@ -68,7 +68,7 @@ nouveau_pwmfan_set(struct drm_device *dev, int percent)
68{ 68{
69 struct drm_nouveau_private *dev_priv = dev->dev_private; 69 struct drm_nouveau_private *dev_priv = dev->dev_private;
70 struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 70 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
71 struct gpio_func gpio; 71 struct dcb_gpio_func gpio;
72 u32 divs, duty; 72 u32 divs, duty;
73 int ret; 73 int ret;
74 74
@@ -555,24 +555,21 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr,
555 struct drm_device *dev = dev_get_drvdata(d); 555 struct drm_device *dev = dev_get_drvdata(d);
556 struct drm_nouveau_private *dev_priv = dev->dev_private; 556 struct drm_nouveau_private *dev_priv = dev->dev_private;
557 struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; 557 struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
558 struct gpio_func gpio;
559 u32 cycles, cur, prev; 558 u32 cycles, cur, prev;
560 u64 start; 559 u64 start;
561 int ret;
562 560
563 ret = nouveau_gpio_find(dev, 0, DCB_GPIO_FAN_SENSE, 0xff, &gpio); 561 if (!nouveau_gpio_func_valid(dev, DCB_GPIO_FAN_SENSE))
564 if (ret) 562 return -ENODEV;
565 return ret;
566 563
567 /* Monitor the GPIO input 0x3b for 250ms. 564 /* Monitor the GPIO input 0x3b for 250ms.
568 * When the fan spins, it changes the value of GPIO FAN_SENSE. 565 * When the fan spins, it changes the value of GPIO FAN_SENSE.
569 * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation. 566 * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation.
570 */ 567 */
571 start = ptimer->read(dev); 568 start = ptimer->read(dev);
572 prev = nouveau_gpio_sense(dev, 0, gpio.line); 569 prev = nouveau_gpio_func_get(dev, DCB_GPIO_FAN_SENSE);
573 cycles = 0; 570 cycles = 0;
574 do { 571 do {
575 cur = nouveau_gpio_sense(dev, 0, gpio.line); 572 cur = nouveau_gpio_func_get(dev, DCB_GPIO_FAN_SENSE);
576 if (prev != cur) { 573 if (prev != cur) {
577 cycles++; 574 cycles++;
578 prev = cur; 575 prev = cur;
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 85cb5f974df..84e03797bec 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -37,7 +37,6 @@
37#include "nouveau_agp.h" 37#include "nouveau_agp.h"
38#include "nouveau_fbcon.h" 38#include "nouveau_fbcon.h"
39#include <core/ramht.h> 39#include <core/ramht.h>
40#include <subdev/gpio.h>
41#include "nouveau_pm.h" 40#include "nouveau_pm.h"
42#include "nv50_display.h" 41#include "nv50_display.h"
43#include <engine/fifo.h> 42#include <engine/fifo.h>
@@ -109,8 +108,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
109 engine->display.destroy = nv04_display_destroy; 108 engine->display.destroy = nv04_display_destroy;
110 engine->display.init = nv04_display_init; 109 engine->display.init = nv04_display_init;
111 engine->display.fini = nv04_display_fini; 110 engine->display.fini = nv04_display_fini;
112 engine->gpio.drive = nv10_gpio_drive;
113 engine->gpio.sense = nv10_gpio_sense;
114 engine->pm.clocks_get = nv04_pm_clocks_get; 111 engine->pm.clocks_get = nv04_pm_clocks_get;
115 engine->pm.clocks_pre = nv04_pm_clocks_pre; 112 engine->pm.clocks_pre = nv04_pm_clocks_pre;
116 engine->pm.clocks_set = nv04_pm_clocks_set; 113 engine->pm.clocks_set = nv04_pm_clocks_set;
@@ -148,8 +145,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
148 engine->display.destroy = nv04_display_destroy; 145 engine->display.destroy = nv04_display_destroy;
149 engine->display.init = nv04_display_init; 146 engine->display.init = nv04_display_init;
150 engine->display.fini = nv04_display_fini; 147 engine->display.fini = nv04_display_fini;
151 engine->gpio.drive = nv10_gpio_drive;
152 engine->gpio.sense = nv10_gpio_sense;
153 engine->pm.clocks_get = nv04_pm_clocks_get; 148 engine->pm.clocks_get = nv04_pm_clocks_get;
154 engine->pm.clocks_pre = nv04_pm_clocks_pre; 149 engine->pm.clocks_pre = nv04_pm_clocks_pre;
155 engine->pm.clocks_set = nv04_pm_clocks_set; 150 engine->pm.clocks_set = nv04_pm_clocks_set;
@@ -183,8 +178,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
183 engine->display.destroy = nv04_display_destroy; 178 engine->display.destroy = nv04_display_destroy;
184 engine->display.init = nv04_display_init; 179 engine->display.init = nv04_display_init;
185 engine->display.fini = nv04_display_fini; 180 engine->display.fini = nv04_display_fini;
186 engine->gpio.drive = nv10_gpio_drive;
187 engine->gpio.sense = nv10_gpio_sense;
188 engine->pm.clocks_get = nv04_pm_clocks_get; 181 engine->pm.clocks_get = nv04_pm_clocks_get;
189 engine->pm.clocks_pre = nv04_pm_clocks_pre; 182 engine->pm.clocks_pre = nv04_pm_clocks_pre;
190 engine->pm.clocks_set = nv04_pm_clocks_set; 183 engine->pm.clocks_set = nv04_pm_clocks_set;
@@ -221,11 +214,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
221 engine->display.destroy = nv04_display_destroy; 214 engine->display.destroy = nv04_display_destroy;
222 engine->display.init = nv04_display_init; 215 engine->display.init = nv04_display_init;
223 engine->display.fini = nv04_display_fini; 216 engine->display.fini = nv04_display_fini;
224 engine->gpio.init = nv10_gpio_init;
225 engine->gpio.fini = nv10_gpio_fini;
226 engine->gpio.drive = nv10_gpio_drive;
227 engine->gpio.sense = nv10_gpio_sense;
228 engine->gpio.irq_enable = nv10_gpio_irq_enable;
229 engine->pm.clocks_get = nv40_pm_clocks_get; 217 engine->pm.clocks_get = nv40_pm_clocks_get;
230 engine->pm.clocks_pre = nv40_pm_clocks_pre; 218 engine->pm.clocks_pre = nv40_pm_clocks_pre;
231 engine->pm.clocks_set = nv40_pm_clocks_set; 219 engine->pm.clocks_set = nv40_pm_clocks_set;
@@ -267,11 +255,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
267 engine->display.destroy = nv50_display_destroy; 255 engine->display.destroy = nv50_display_destroy;
268 engine->display.init = nv50_display_init; 256 engine->display.init = nv50_display_init;
269 engine->display.fini = nv50_display_fini; 257 engine->display.fini = nv50_display_fini;
270 engine->gpio.init = nv50_gpio_init;
271 engine->gpio.fini = nv50_gpio_fini;
272 engine->gpio.drive = nv50_gpio_drive;
273 engine->gpio.sense = nv50_gpio_sense;
274 engine->gpio.irq_enable = nv50_gpio_irq_enable;
275 switch (dev_priv->chipset) { 258 switch (dev_priv->chipset) {
276 case 0x84: 259 case 0x84:
277 case 0x86: 260 case 0x86:
@@ -330,11 +313,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
330 engine->display.destroy = nv50_display_destroy; 313 engine->display.destroy = nv50_display_destroy;
331 engine->display.init = nv50_display_init; 314 engine->display.init = nv50_display_init;
332 engine->display.fini = nv50_display_fini; 315 engine->display.fini = nv50_display_fini;
333 engine->gpio.init = nv50_gpio_init;
334 engine->gpio.fini = nv50_gpio_fini;
335 engine->gpio.drive = nv50_gpio_drive;
336 engine->gpio.sense = nv50_gpio_sense;
337 engine->gpio.irq_enable = nv50_gpio_irq_enable;
338 engine->vram.init = nvc0_vram_init; 316 engine->vram.init = nvc0_vram_init;
339 engine->vram.takedown = nv50_vram_fini; 317 engine->vram.takedown = nv50_vram_fini;
340 engine->vram.get = nvc0_vram_new; 318 engine->vram.get = nvc0_vram_new;
@@ -372,11 +350,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
372 engine->display.destroy = nvd0_display_destroy; 350 engine->display.destroy = nvd0_display_destroy;
373 engine->display.init = nvd0_display_init; 351 engine->display.init = nvd0_display_init;
374 engine->display.fini = nvd0_display_fini; 352 engine->display.fini = nvd0_display_fini;
375 engine->gpio.init = nv50_gpio_init;
376 engine->gpio.fini = nv50_gpio_fini;
377 engine->gpio.drive = nvd0_gpio_drive;
378 engine->gpio.sense = nvd0_gpio_sense;
379 engine->gpio.irq_enable = nv50_gpio_irq_enable;
380 engine->vram.init = nvc0_vram_init; 353 engine->vram.init = nvc0_vram_init;
381 engine->vram.takedown = nv50_vram_fini; 354 engine->vram.takedown = nv50_vram_fini;
382 engine->vram.get = nvc0_vram_new; 355 engine->vram.get = nvc0_vram_new;
@@ -412,11 +385,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
412 engine->display.destroy = nvd0_display_destroy; 385 engine->display.destroy = nvd0_display_destroy;
413 engine->display.init = nvd0_display_init; 386 engine->display.init = nvd0_display_init;
414 engine->display.fini = nvd0_display_fini; 387 engine->display.fini = nvd0_display_fini;
415 engine->gpio.init = nv50_gpio_init;
416 engine->gpio.fini = nv50_gpio_fini;
417 engine->gpio.drive = nvd0_gpio_drive;
418 engine->gpio.sense = nvd0_gpio_sense;
419 engine->gpio.irq_enable = nv50_gpio_irq_enable;
420 engine->vram.init = nvc0_vram_init; 388 engine->vram.init = nvc0_vram_init;
421 engine->vram.takedown = nv50_vram_fini; 389 engine->vram.takedown = nv50_vram_fini;
422 engine->vram.get = nvc0_vram_new; 390 engine->vram.get = nvc0_vram_new;
@@ -588,14 +556,9 @@ nouveau_card_init(struct drm_device *dev)
588 if (ret) 556 if (ret)
589 goto out_fb; 557 goto out_fb;
590 558
591 /* PGPIO */
592 ret = nouveau_gpio_create(dev);
593 if (ret)
594 goto out_vram;
595
596 ret = nouveau_gpuobj_init(dev); 559 ret = nouveau_gpuobj_init(dev);
597 if (ret) 560 if (ret)
598 goto out_gpio; 561 goto out_vram;
599 562
600 ret = engine->instmem.init(dev); 563 ret = engine->instmem.init(dev);
601 if (ret) 564 if (ret)
@@ -830,8 +793,6 @@ out_instmem:
830 engine->instmem.takedown(dev); 793 engine->instmem.takedown(dev);
831out_gpuobj: 794out_gpuobj:
832 nouveau_gpuobj_takedown(dev); 795 nouveau_gpuobj_takedown(dev);
833out_gpio:
834 nouveau_gpio_destroy(dev);
835out_vram: 796out_vram:
836 engine->vram.takedown(dev); 797 engine->vram.takedown(dev);
837out_fb: 798out_fb:
@@ -890,7 +851,6 @@ static void nouveau_card_takedown(struct drm_device *dev)
890 engine->instmem.takedown(dev); 851 engine->instmem.takedown(dev);
891 nouveau_gpuobj_takedown(dev); 852 nouveau_gpuobj_takedown(dev);
892 853
893 nouveau_gpio_destroy(dev);
894 engine->vram.takedown(dev); 854 engine->vram.takedown(dev);
895 engine->fb.takedown(dev); 855 engine->fb.takedown(dev);
896 engine->timer.takedown(dev); 856 engine->timer.takedown(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c
index 9e34b573b8d..da3222c5a30 100644
--- a/drivers/gpu/drm/nouveau/nouveau_volt.c
+++ b/drivers/gpu/drm/nouveau/nouveau_volt.c
@@ -26,9 +26,10 @@
26 26
27#include "nouveau_drv.h" 27#include "nouveau_drv.h"
28#include "nouveau_pm.h" 28#include "nouveau_pm.h"
29#include <subdev/gpio.h>
30 29
31static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 }; 30#include <subdev/bios/gpio.h>
31
32static const enum dcb_gpio_func_name vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 };
32static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]); 33static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]);
33 34
34int 35int
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
index da091a1caed..54deb2779f8 100644
--- a/drivers/gpu/drm/nouveau/nv04_dac.c
+++ b/drivers/gpu/drm/nouveau/nv04_dac.c
@@ -32,9 +32,10 @@
32#include "nouveau_connector.h" 32#include "nouveau_connector.h"
33#include "nouveau_crtc.h" 33#include "nouveau_crtc.h"
34#include "nouveau_hw.h" 34#include "nouveau_hw.h"
35#include <subdev/gpio.h>
36#include "nvreg.h" 35#include "nvreg.h"
37 36
37#include <subdev/bios/gpio.h>
38
38int nv04_dac_output_offset(struct drm_encoder *encoder) 39int nv04_dac_output_offset(struct drm_encoder *encoder)
39{ 40{
40 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; 41 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c
index 65f7c452e47..a66a348d7f2 100644
--- a/drivers/gpu/drm/nouveau/nv17_tv.c
+++ b/drivers/gpu/drm/nouveau/nv17_tv.c
@@ -30,10 +30,11 @@
30#include "nouveau_encoder.h" 30#include "nouveau_encoder.h"
31#include "nouveau_connector.h" 31#include "nouveau_connector.h"
32#include "nouveau_crtc.h" 32#include "nouveau_crtc.h"
33#include <subdev/gpio.h>
34#include "nouveau_hw.h" 33#include "nouveau_hw.h"
35#include "nv17_tv.h" 34#include "nv17_tv.h"
36 35
36#include <subdev/bios/gpio.h>
37
37static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) 38static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
38{ 39{
39 struct drm_device *dev = encoder->dev; 40 struct drm_device *dev = encoder->dev;