aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/Makefile8
-rw-r--r--drivers/gpu/drm/nouveau/core/core/event.c83
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/gm100.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv04.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv10.c32
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv20.c16
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv30.c20
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv40.c64
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv50.c56
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nvc0.c36
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nve0.c24
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/base.c124
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/conn.c172
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/conn.h59
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/dport.c290
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/dport.h37
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/gm107.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv04.c8
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c286
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.h14
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv84.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv94.c11
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nva0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nva3.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c206
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nve0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outp.c137
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outp.h59
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c276
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h65
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c122
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/priv.h32
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c28
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c85
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c72
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/base.c6
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c6
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c6
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nv50.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nv50.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nvc0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/class.h4
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/event.h29
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/disp.h30
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h22
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h9
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/gpio.h34
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/i2c.h83
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/conn.c62
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/dp.c23
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/init.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/base.c130
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c115
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c152
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c74
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c56
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c137
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h62
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c27
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c36
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/base.c212
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c8
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c33
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c33
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c30
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c108
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c38
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c72
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c84
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h58
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c35
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c86
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/port.h15
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h85
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c208
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_crtc.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c14
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c101
90 files changed, 3346 insertions, 1486 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 1aaa2ef577d9..2b6156d0e4b5 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -125,17 +125,22 @@ nouveau-y += core/subdev/fb/gddr5.o
125nouveau-y += core/subdev/gpio/base.o 125nouveau-y += core/subdev/gpio/base.o
126nouveau-y += core/subdev/gpio/nv10.o 126nouveau-y += core/subdev/gpio/nv10.o
127nouveau-y += core/subdev/gpio/nv50.o 127nouveau-y += core/subdev/gpio/nv50.o
128nouveau-y += core/subdev/gpio/nv92.o
128nouveau-y += core/subdev/gpio/nvd0.o 129nouveau-y += core/subdev/gpio/nvd0.o
129nouveau-y += core/subdev/gpio/nve0.o 130nouveau-y += core/subdev/gpio/nve0.o
130nouveau-y += core/subdev/i2c/base.o 131nouveau-y += core/subdev/i2c/base.o
131nouveau-y += core/subdev/i2c/anx9805.o 132nouveau-y += core/subdev/i2c/anx9805.o
132nouveau-y += core/subdev/i2c/aux.o 133nouveau-y += core/subdev/i2c/aux.o
133nouveau-y += core/subdev/i2c/bit.o 134nouveau-y += core/subdev/i2c/bit.o
135nouveau-y += core/subdev/i2c/pad.o
136nouveau-y += core/subdev/i2c/padnv04.o
137nouveau-y += core/subdev/i2c/padnv94.o
134nouveau-y += core/subdev/i2c/nv04.o 138nouveau-y += core/subdev/i2c/nv04.o
135nouveau-y += core/subdev/i2c/nv4e.o 139nouveau-y += core/subdev/i2c/nv4e.o
136nouveau-y += core/subdev/i2c/nv50.o 140nouveau-y += core/subdev/i2c/nv50.o
137nouveau-y += core/subdev/i2c/nv94.o 141nouveau-y += core/subdev/i2c/nv94.o
138nouveau-y += core/subdev/i2c/nvd0.o 142nouveau-y += core/subdev/i2c/nvd0.o
143nouveau-y += core/subdev/i2c/nve0.o
139nouveau-y += core/subdev/ibus/nvc0.o 144nouveau-y += core/subdev/ibus/nvc0.o
140nouveau-y += core/subdev/ibus/nve0.o 145nouveau-y += core/subdev/ibus/nve0.o
141nouveau-y += core/subdev/ibus/gk20a.o 146nouveau-y += core/subdev/ibus/gk20a.o
@@ -217,6 +222,9 @@ nouveau-y += core/engine/device/nvc0.o
217nouveau-y += core/engine/device/nve0.o 222nouveau-y += core/engine/device/nve0.o
218nouveau-y += core/engine/device/gm100.o 223nouveau-y += core/engine/device/gm100.o
219nouveau-y += core/engine/disp/base.o 224nouveau-y += core/engine/disp/base.o
225nouveau-y += core/engine/disp/conn.o
226nouveau-y += core/engine/disp/outp.o
227nouveau-y += core/engine/disp/outpdp.o
220nouveau-y += core/engine/disp/nv04.o 228nouveau-y += core/engine/disp/nv04.o
221nouveau-y += core/engine/disp/nv50.o 229nouveau-y += core/engine/disp/nv50.o
222nouveau-y += core/engine/disp/nv84.o 230nouveau-y += core/engine/disp/nv84.o
diff --git a/drivers/gpu/drm/nouveau/core/core/event.c b/drivers/gpu/drm/nouveau/core/core/event.c
index 3f3c76581a9e..ae81d3b5d8b7 100644
--- a/drivers/gpu/drm/nouveau/core/core/event.c
+++ b/drivers/gpu/drm/nouveau/core/core/event.c
@@ -28,14 +28,20 @@ nouveau_event_put(struct nouveau_eventh *handler)
28{ 28{
29 struct nouveau_event *event = handler->event; 29 struct nouveau_event *event = handler->event;
30 unsigned long flags; 30 unsigned long flags;
31 if (__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags)) { 31 u32 m, t;
32 spin_lock_irqsave(&event->refs_lock, flags); 32
33 if (!--event->index[handler->index].refs) { 33 if (!__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags))
34 return;
35
36 spin_lock_irqsave(&event->refs_lock, flags);
37 for (m = handler->types; t = __ffs(m), m; m &= ~(1 << t)) {
38 if (!--event->refs[handler->index * event->types_nr + t]) {
34 if (event->disable) 39 if (event->disable)
35 event->disable(event, handler->index); 40 event->disable(event, 1 << t, handler->index);
36 } 41 }
37 spin_unlock_irqrestore(&event->refs_lock, flags); 42
38 } 43 }
44 spin_unlock_irqrestore(&event->refs_lock, flags);
39} 45}
40 46
41void 47void
@@ -43,14 +49,20 @@ nouveau_event_get(struct nouveau_eventh *handler)
43{ 49{
44 struct nouveau_event *event = handler->event; 50 struct nouveau_event *event = handler->event;
45 unsigned long flags; 51 unsigned long flags;
46 if (!__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) { 52 u32 m, t;
47 spin_lock_irqsave(&event->refs_lock, flags); 53
48 if (!event->index[handler->index].refs++) { 54 if (__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags))
55 return;
56
57 spin_lock_irqsave(&event->refs_lock, flags);
58 for (m = handler->types; t = __ffs(m), m; m &= ~(1 << t)) {
59 if (!event->refs[handler->index * event->types_nr + t]++) {
49 if (event->enable) 60 if (event->enable)
50 event->enable(event, handler->index); 61 event->enable(event, 1 << t, handler->index);
51 } 62 }
52 spin_unlock_irqrestore(&event->refs_lock, flags); 63
53 } 64 }
65 spin_unlock_irqrestore(&event->refs_lock, flags);
54} 66}
55 67
56static void 68static void
@@ -65,38 +77,47 @@ nouveau_event_fini(struct nouveau_eventh *handler)
65} 77}
66 78
67static int 79static int
68nouveau_event_init(struct nouveau_event *event, int index, 80nouveau_event_init(struct nouveau_event *event, u32 types, int index,
69 int (*func)(void *, int), void *priv, 81 int (*func)(void *, u32, int), void *priv,
70 struct nouveau_eventh *handler) 82 struct nouveau_eventh *handler)
71{ 83{
72 unsigned long flags; 84 unsigned long flags;
73 85
86 if (types & ~((1 << event->types_nr) - 1))
87 return -EINVAL;
74 if (index >= event->index_nr) 88 if (index >= event->index_nr)
75 return -EINVAL; 89 return -EINVAL;
76 90
77 handler->event = event; 91 handler->event = event;
78 handler->flags = 0; 92 handler->flags = 0;
93 handler->types = types;
79 handler->index = index; 94 handler->index = index;
80 handler->func = func; 95 handler->func = func;
81 handler->priv = priv; 96 handler->priv = priv;
82 97
83 spin_lock_irqsave(&event->list_lock, flags); 98 spin_lock_irqsave(&event->list_lock, flags);
84 list_add_tail(&handler->head, &event->index[index].list); 99 list_add_tail(&handler->head, &event->list[index]);
85 spin_unlock_irqrestore(&event->list_lock, flags); 100 spin_unlock_irqrestore(&event->list_lock, flags);
86 return 0; 101 return 0;
87} 102}
88 103
89int 104int
90nouveau_event_new(struct nouveau_event *event, int index, 105nouveau_event_new(struct nouveau_event *event, u32 types, int index,
91 int (*func)(void *, int), void *priv, 106 int (*func)(void *, u32, int), void *priv,
92 struct nouveau_eventh **phandler) 107 struct nouveau_eventh **phandler)
93{ 108{
94 struct nouveau_eventh *handler; 109 struct nouveau_eventh *handler;
95 int ret = -ENOMEM; 110 int ret = -ENOMEM;
96 111
112 if (event->check) {
113 ret = event->check(event, types, index);
114 if (ret)
115 return ret;
116 }
117
97 handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL); 118 handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL);
98 if (handler) { 119 if (handler) {
99 ret = nouveau_event_init(event, index, func, priv, handler); 120 ret = nouveau_event_init(event, types, index, func, priv, handler);
100 if (ret) 121 if (ret)
101 kfree(handler); 122 kfree(handler);
102 } 123 }
@@ -116,7 +137,7 @@ nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref)
116} 137}
117 138
118void 139void
119nouveau_event_trigger(struct nouveau_event *event, int index) 140nouveau_event_trigger(struct nouveau_event *event, u32 types, int index)
120{ 141{
121 struct nouveau_eventh *handler; 142 struct nouveau_eventh *handler;
122 unsigned long flags; 143 unsigned long flags;
@@ -125,10 +146,15 @@ nouveau_event_trigger(struct nouveau_event *event, int index)
125 return; 146 return;
126 147
127 spin_lock_irqsave(&event->list_lock, flags); 148 spin_lock_irqsave(&event->list_lock, flags);
128 list_for_each_entry(handler, &event->index[index].list, head) { 149 list_for_each_entry(handler, &event->list[index], head) {
129 if (test_bit(NVKM_EVENT_ENABLE, &handler->flags) && 150 if (!test_bit(NVKM_EVENT_ENABLE, &handler->flags))
130 handler->func(handler->priv, index) == NVKM_EVENT_DROP) 151 continue;
131 nouveau_event_put(handler); 152 if (!(handler->types & types))
153 continue;
154 if (handler->func(handler->priv, handler->types & types, index)
155 != NVKM_EVENT_DROP)
156 continue;
157 nouveau_event_put(handler);
132 } 158 }
133 spin_unlock_irqrestore(&event->list_lock, flags); 159 spin_unlock_irqrestore(&event->list_lock, flags);
134} 160}
@@ -144,20 +170,27 @@ nouveau_event_destroy(struct nouveau_event **pevent)
144} 170}
145 171
146int 172int
147nouveau_event_create(int index_nr, struct nouveau_event **pevent) 173nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **pevent)
148{ 174{
149 struct nouveau_event *event; 175 struct nouveau_event *event;
150 int i; 176 int i;
151 177
152 event = *pevent = kzalloc(sizeof(*event) + index_nr * 178 event = *pevent = kzalloc(sizeof(*event) + (index_nr * types_nr) *
153 sizeof(event->index[0]), GFP_KERNEL); 179 sizeof(event->refs[0]), GFP_KERNEL);
154 if (!event) 180 if (!event)
155 return -ENOMEM; 181 return -ENOMEM;
156 182
183 event->list = kmalloc(sizeof(*event->list) * index_nr, GFP_KERNEL);
184 if (!event->list) {
185 kfree(event);
186 return -ENOMEM;
187 }
188
157 spin_lock_init(&event->list_lock); 189 spin_lock_init(&event->list_lock);
158 spin_lock_init(&event->refs_lock); 190 spin_lock_init(&event->refs_lock);
159 for (i = 0; i < index_nr; i++) 191 for (i = 0; i < index_nr; i++)
160 INIT_LIST_HEAD(&event->index[i].list); 192 INIT_LIST_HEAD(&event->list[i]);
193 event->types_nr = types_nr;
161 event->index_nr = index_nr; 194 event->index_nr = index_nr;
162 return 0; 195 return 0;
163} 196}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c
index d258c21c4a22..a520029e25d9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c
@@ -60,8 +60,8 @@ gm100_identify(struct nouveau_device *device)
60 case 0x117: 60 case 0x117:
61 device->cname = "GM107"; 61 device->cname = "GM107";
62 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 62 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
63 device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; 63 device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
64 device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; 64 device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
65 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; 65 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
66#if 0 66#if 0
67 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; 67 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c b/drivers/gpu/drm/nouveau/core/engine/device/nv04.c
index 0a51ff4e9e00..40b29d0214cb 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nv04.c
@@ -47,7 +47,7 @@ nv04_identify(struct nouveau_device *device)
47 case 0x04: 47 case 0x04:
48 device->cname = "NV04"; 48 device->cname = "NV04";
49 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 49 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
50 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 50 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
51 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 51 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
52 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass; 52 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass;
53 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 53 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -65,7 +65,7 @@ nv04_identify(struct nouveau_device *device)
65 case 0x05: 65 case 0x05:
66 device->cname = "NV05"; 66 device->cname = "NV05";
67 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 67 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
68 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 68 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
69 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 69 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
70 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass; 70 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass;
71 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 71 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c b/drivers/gpu/drm/nouveau/core/engine/device/nv10.c
index e008de8b51b0..5f7c25ff523d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nv10.c
@@ -48,8 +48,8 @@ nv10_identify(struct nouveau_device *device)
48 case 0x10: 48 case 0x10:
49 device->cname = "NV10"; 49 device->cname = "NV10";
50 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; 51 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
52 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 52 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
53 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 53 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
54 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; 54 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
55 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 55 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -65,8 +65,8 @@ nv10_identify(struct nouveau_device *device)
65 case 0x15: 65 case 0x15:
66 device->cname = "NV15"; 66 device->cname = "NV15";
67 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 67 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
68 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 68 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
69 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 69 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
70 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 70 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
71 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; 71 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
72 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 72 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -84,8 +84,8 @@ nv10_identify(struct nouveau_device *device)
84 case 0x16: 84 case 0x16:
85 device->cname = "NV16"; 85 device->cname = "NV16";
86 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; 87 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
88 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 88 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
89 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 89 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
90 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; 90 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
91 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 91 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -103,8 +103,8 @@ nv10_identify(struct nouveau_device *device)
103 case 0x1a: 103 case 0x1a:
104 device->cname = "nForce"; 104 device->cname = "nForce";
105 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 105 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
106 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 106 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
107 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 107 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
108 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 108 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
109 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 109 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
110 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 110 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -122,8 +122,8 @@ nv10_identify(struct nouveau_device *device)
122 case 0x11: 122 case 0x11:
123 device->cname = "NV11"; 123 device->cname = "NV11";
124 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 124 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
125 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 125 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
126 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 126 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
127 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 127 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
128 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; 128 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
129 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 129 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -141,8 +141,8 @@ nv10_identify(struct nouveau_device *device)
141 case 0x17: 141 case 0x17:
142 device->cname = "NV17"; 142 device->cname = "NV17";
143 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 143 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
144 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 144 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
145 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 145 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
146 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 146 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
147 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; 147 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
148 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 148 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -160,8 +160,8 @@ nv10_identify(struct nouveau_device *device)
160 case 0x1f: 160 case 0x1f:
161 device->cname = "nForce2"; 161 device->cname = "nForce2";
162 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 162 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
163 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 163 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
164 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 164 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
165 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 165 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
166 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 166 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
167 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 167 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -179,8 +179,8 @@ nv10_identify(struct nouveau_device *device)
179 case 0x18: 179 case 0x18:
180 device->cname = "NV18"; 180 device->cname = "NV18";
181 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 181 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
182 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 182 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
183 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 183 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
184 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 184 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
185 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; 185 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
186 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 186 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c b/drivers/gpu/drm/nouveau/core/engine/device/nv20.c
index 7b629a3aed05..75fed11bba0a 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nv20.c
@@ -49,8 +49,8 @@ nv20_identify(struct nouveau_device *device)
49 case 0x20: 49 case 0x20:
50 device->cname = "NV20"; 50 device->cname = "NV20";
51 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 51 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
52 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 52 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
53 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 53 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
54 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 54 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
55 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; 55 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
56 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 56 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -68,8 +68,8 @@ nv20_identify(struct nouveau_device *device)
68 case 0x25: 68 case 0x25:
69 device->cname = "NV25"; 69 device->cname = "NV25";
70 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; 71 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
72 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 72 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
73 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 73 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
74 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; 74 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
75 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 75 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -87,8 +87,8 @@ nv20_identify(struct nouveau_device *device)
87 case 0x28: 87 case 0x28:
88 device->cname = "NV28"; 88 device->cname = "NV28";
89 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 89 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
90 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 90 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
91 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 91 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
92 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 92 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
93 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; 93 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
94 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 94 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -106,8 +106,8 @@ nv20_identify(struct nouveau_device *device)
106 case 0x2a: 106 case 0x2a:
107 device->cname = "NV2A"; 107 device->cname = "NV2A";
108 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 108 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
109 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 109 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
110 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 110 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
111 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 111 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
112 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; 112 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
113 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 113 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c b/drivers/gpu/drm/nouveau/core/engine/device/nv30.c
index 7dfddd5a1908..36919d7db7cc 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nv30.c
@@ -49,8 +49,8 @@ nv30_identify(struct nouveau_device *device)
49 case 0x30: 49 case 0x30:
50 device->cname = "NV30"; 50 device->cname = "NV30";
51 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 51 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
52 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 52 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
53 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 53 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
54 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 54 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
55 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; 55 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
56 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 56 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -68,8 +68,8 @@ nv30_identify(struct nouveau_device *device)
68 case 0x35: 68 case 0x35:
69 device->cname = "NV35"; 69 device->cname = "NV35";
70 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; 71 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
72 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 72 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
73 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 73 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
74 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; 74 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
75 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 75 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -87,8 +87,8 @@ nv30_identify(struct nouveau_device *device)
87 case 0x31: 87 case 0x31:
88 device->cname = "NV31"; 88 device->cname = "NV31";
89 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 89 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
90 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 90 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
91 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 91 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
92 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 92 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
93 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; 93 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
94 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 94 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -107,8 +107,8 @@ nv30_identify(struct nouveau_device *device)
107 case 0x36: 107 case 0x36:
108 device->cname = "NV36"; 108 device->cname = "NV36";
109 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 109 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
110 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 110 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
111 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 111 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
112 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 112 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
113 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; 113 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
114 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 114 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
@@ -127,8 +127,8 @@ nv30_identify(struct nouveau_device *device)
127 case 0x34: 127 case 0x34:
128 device->cname = "NV34"; 128 device->cname = "NV34";
129 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 129 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
130 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 130 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
131 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 131 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
132 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; 132 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
133 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; 133 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
134 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; 134 device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
index 7c1ce6cf4f1f..1130a62be2c7 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
@@ -53,8 +53,8 @@ nv40_identify(struct nouveau_device *device)
53 case 0x40: 53 case 0x40:
54 device->cname = "NV40"; 54 device->cname = "NV40";
55 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 55 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
56 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 56 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
57 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 57 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
58 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 58 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
59 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 59 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
60 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 60 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -76,8 +76,8 @@ nv40_identify(struct nouveau_device *device)
76 case 0x41: 76 case 0x41:
77 device->cname = "NV41"; 77 device->cname = "NV41";
78 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; 79 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
80 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 80 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
81 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 81 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
82 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 82 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
83 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 83 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -99,8 +99,8 @@ nv40_identify(struct nouveau_device *device)
99 case 0x42: 99 case 0x42:
100 device->cname = "NV42"; 100 device->cname = "NV42";
101 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 101 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
102 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 102 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
103 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 103 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
104 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 104 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
105 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 105 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
106 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 106 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -122,8 +122,8 @@ nv40_identify(struct nouveau_device *device)
122 case 0x43: 122 case 0x43:
123 device->cname = "NV43"; 123 device->cname = "NV43";
124 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 124 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
125 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 125 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
126 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 126 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
127 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 127 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
128 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 128 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
129 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 129 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -145,8 +145,8 @@ nv40_identify(struct nouveau_device *device)
145 case 0x45: 145 case 0x45:
146 device->cname = "NV45"; 146 device->cname = "NV45";
147 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 147 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
148 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 148 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
149 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 149 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
150 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 150 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
151 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 151 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
152 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 152 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -168,8 +168,8 @@ nv40_identify(struct nouveau_device *device)
168 case 0x47: 168 case 0x47:
169 device->cname = "G70"; 169 device->cname = "G70";
170 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 170 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
171 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 171 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
172 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 172 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
173 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 173 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
174 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 174 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
175 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 175 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -191,8 +191,8 @@ nv40_identify(struct nouveau_device *device)
191 case 0x49: 191 case 0x49:
192 device->cname = "G71"; 192 device->cname = "G71";
193 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 193 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
194 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 194 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
195 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 195 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
196 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 196 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
197 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 197 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
198 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 198 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -214,8 +214,8 @@ nv40_identify(struct nouveau_device *device)
214 case 0x4b: 214 case 0x4b:
215 device->cname = "G73"; 215 device->cname = "G73";
216 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 216 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
217 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 217 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
218 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 218 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
219 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 219 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
220 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 220 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
221 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 221 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -237,8 +237,8 @@ nv40_identify(struct nouveau_device *device)
237 case 0x44: 237 case 0x44:
238 device->cname = "NV44"; 238 device->cname = "NV44";
239 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 239 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
240 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 240 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
241 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 241 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
242 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 242 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
243 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 243 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
244 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 244 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -260,8 +260,8 @@ nv40_identify(struct nouveau_device *device)
260 case 0x46: 260 case 0x46:
261 device->cname = "G72"; 261 device->cname = "G72";
262 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 262 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
263 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 263 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
264 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 264 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
265 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 265 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
266 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 266 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
267 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 267 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -283,8 +283,8 @@ nv40_identify(struct nouveau_device *device)
283 case 0x4a: 283 case 0x4a:
284 device->cname = "NV44A"; 284 device->cname = "NV44A";
285 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 285 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
286 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 286 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
287 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 287 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
288 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 288 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
289 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 289 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
290 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 290 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -306,8 +306,8 @@ nv40_identify(struct nouveau_device *device)
306 case 0x4c: 306 case 0x4c:
307 device->cname = "C61"; 307 device->cname = "C61";
308 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 308 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
309 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 309 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
310 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 310 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
311 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 311 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
312 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 312 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
313 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 313 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -329,8 +329,8 @@ nv40_identify(struct nouveau_device *device)
329 case 0x4e: 329 case 0x4e:
330 device->cname = "C51"; 330 device->cname = "C51";
331 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 331 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
332 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 332 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
333 device->oclass[NVDEV_SUBDEV_I2C ] = &nv4e_i2c_oclass; 333 device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass;
334 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 334 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
335 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 335 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
336 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 336 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -352,8 +352,8 @@ nv40_identify(struct nouveau_device *device)
352 case 0x63: 352 case 0x63:
353 device->cname = "C73"; 353 device->cname = "C73";
354 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 354 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
355 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 355 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
356 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 356 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
357 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 357 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
358 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 358 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
359 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 359 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -375,8 +375,8 @@ nv40_identify(struct nouveau_device *device)
375 case 0x67: 375 case 0x67:
376 device->cname = "C67"; 376 device->cname = "C67";
377 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 377 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
378 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 378 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
379 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 379 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
380 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 380 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
381 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 381 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
382 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 382 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
@@ -398,8 +398,8 @@ nv40_identify(struct nouveau_device *device)
398 case 0x68: 398 case 0x68:
399 device->cname = "C68"; 399 device->cname = "C68";
400 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 400 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
401 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 401 device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
402 device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; 402 device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
403 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 403 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
404 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; 404 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
405 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; 405 device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
index 66499fa0f758..ef0b0bde1a91 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
@@ -60,8 +60,8 @@ nv50_identify(struct nouveau_device *device)
60 case 0x50: 60 case 0x50:
61 device->cname = "G80"; 61 device->cname = "G80";
62 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; 63 device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
64 device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; 64 device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
65 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv50_clock_oclass; 65 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv50_clock_oclass;
66 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; 66 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
67 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 67 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -85,8 +85,8 @@ nv50_identify(struct nouveau_device *device)
85 case 0x84: 85 case 0x84:
86 device->cname = "G84"; 86 device->cname = "G84";
87 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 87 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
88 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 88 device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
89 device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; 89 device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
90 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; 90 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
91 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; 91 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
92 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 92 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -113,8 +113,8 @@ nv50_identify(struct nouveau_device *device)
113 case 0x86: 113 case 0x86:
114 device->cname = "G86"; 114 device->cname = "G86";
115 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 115 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
116 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 116 device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
117 device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; 117 device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
118 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; 118 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
119 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; 119 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
120 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 120 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -141,8 +141,8 @@ nv50_identify(struct nouveau_device *device)
141 case 0x92: 141 case 0x92:
142 device->cname = "G92"; 142 device->cname = "G92";
143 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 143 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
144 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 144 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
145 device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; 145 device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
146 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; 146 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
147 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; 147 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
148 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 148 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -169,8 +169,8 @@ nv50_identify(struct nouveau_device *device)
169 case 0x94: 169 case 0x94:
170 device->cname = "G94"; 170 device->cname = "G94";
171 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 171 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
172 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 172 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
173 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 173 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
174 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; 174 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
175 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; 175 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
176 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 176 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -197,8 +197,8 @@ nv50_identify(struct nouveau_device *device)
197 case 0x96: 197 case 0x96:
198 device->cname = "G96"; 198 device->cname = "G96";
199 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 199 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
200 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 200 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
201 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 201 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
202 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; 202 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
203 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; 203 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
204 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 204 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -225,8 +225,8 @@ nv50_identify(struct nouveau_device *device)
225 case 0x98: 225 case 0x98:
226 device->cname = "G98"; 226 device->cname = "G98";
227 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 227 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
228 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 228 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
229 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 229 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
230 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; 230 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
231 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; 231 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
232 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 232 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -253,8 +253,8 @@ nv50_identify(struct nouveau_device *device)
253 case 0xa0: 253 case 0xa0:
254 device->cname = "G200"; 254 device->cname = "G200";
255 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 255 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
256 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 256 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
257 device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; 257 device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
258 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; 258 device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
259 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; 259 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
260 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 260 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -281,8 +281,8 @@ nv50_identify(struct nouveau_device *device)
281 case 0xaa: 281 case 0xaa:
282 device->cname = "MCP77/MCP78"; 282 device->cname = "MCP77/MCP78";
283 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 283 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
284 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 284 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
285 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 285 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
286 device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass; 286 device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass;
287 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; 287 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
288 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 288 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -309,8 +309,8 @@ nv50_identify(struct nouveau_device *device)
309 case 0xac: 309 case 0xac:
310 device->cname = "MCP79/MCP7A"; 310 device->cname = "MCP79/MCP7A";
311 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 311 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
312 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 312 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
313 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 313 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
314 device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass; 314 device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass;
315 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; 315 device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
316 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 316 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -337,8 +337,8 @@ nv50_identify(struct nouveau_device *device)
337 case 0xa3: 337 case 0xa3:
338 device->cname = "GT215"; 338 device->cname = "GT215";
339 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 339 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
340 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 340 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
341 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 341 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
342 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; 342 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
343 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 343 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
344 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 344 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -367,8 +367,8 @@ nv50_identify(struct nouveau_device *device)
367 case 0xa5: 367 case 0xa5:
368 device->cname = "GT216"; 368 device->cname = "GT216";
369 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 369 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
370 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 370 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
371 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 371 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
372 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; 372 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
373 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 373 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
374 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 374 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -396,8 +396,8 @@ nv50_identify(struct nouveau_device *device)
396 case 0xa8: 396 case 0xa8:
397 device->cname = "GT218"; 397 device->cname = "GT218";
398 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 398 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
399 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 399 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
400 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 400 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
401 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; 401 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
402 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 402 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
403 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 403 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -425,8 +425,8 @@ nv50_identify(struct nouveau_device *device)
425 case 0xaf: 425 case 0xaf:
426 device->cname = "MCP89"; 426 device->cname = "MCP89";
427 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 427 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
428 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 428 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
429 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 429 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
430 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; 430 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
431 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 431 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
432 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 432 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
index 2075b3027052..f199957995fa 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
@@ -60,8 +60,8 @@ nvc0_identify(struct nouveau_device *device)
60 case 0xc0: 60 case 0xc0:
61 device->cname = "GF100"; 61 device->cname = "GF100";
62 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; 63 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
64 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 64 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
65 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 65 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
66 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 66 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
67 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 67 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -92,8 +92,8 @@ nvc0_identify(struct nouveau_device *device)
92 case 0xc4: 92 case 0xc4:
93 device->cname = "GF104"; 93 device->cname = "GF104";
94 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 94 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
95 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 95 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
96 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 96 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
97 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 97 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
98 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 98 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
99 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 99 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -124,8 +124,8 @@ nvc0_identify(struct nouveau_device *device)
124 case 0xc3: 124 case 0xc3:
125 device->cname = "GF106"; 125 device->cname = "GF106";
126 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 126 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
127 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 127 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
128 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 128 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
129 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 129 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
130 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 130 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
131 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 131 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -155,8 +155,8 @@ nvc0_identify(struct nouveau_device *device)
155 case 0xce: 155 case 0xce:
156 device->cname = "GF114"; 156 device->cname = "GF114";
157 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 157 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
158 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 158 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
159 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 159 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
160 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 160 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
161 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 161 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
162 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 162 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -187,8 +187,8 @@ nvc0_identify(struct nouveau_device *device)
187 case 0xcf: 187 case 0xcf:
188 device->cname = "GF116"; 188 device->cname = "GF116";
189 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 189 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
190 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 190 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
191 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 191 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
192 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 192 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
193 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 193 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
194 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 194 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -219,8 +219,8 @@ nvc0_identify(struct nouveau_device *device)
219 case 0xc1: 219 case 0xc1:
220 device->cname = "GF108"; 220 device->cname = "GF108";
221 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 221 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
222 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 222 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
223 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 223 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
224 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 224 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
225 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 225 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
226 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 226 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -250,8 +250,8 @@ nvc0_identify(struct nouveau_device *device)
250 case 0xc8: 250 case 0xc8:
251 device->cname = "GF110"; 251 device->cname = "GF110";
252 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 252 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
253 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 253 device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
254 device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; 254 device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
255 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 255 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
256 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 256 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
257 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 257 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -282,8 +282,8 @@ nvc0_identify(struct nouveau_device *device)
282 case 0xd9: 282 case 0xd9:
283 device->cname = "GF119"; 283 device->cname = "GF119";
284 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 284 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
285 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; 285 device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass;
286 device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; 286 device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
287 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 287 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
288 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; 288 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
289 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 289 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -313,8 +313,8 @@ nvc0_identify(struct nouveau_device *device)
313 case 0xd7: 313 case 0xd7:
314 device->cname = "GF117"; 314 device->cname = "GF117";
315 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 315 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
316 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; 316 device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass;
317 device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; 317 device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
318 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 318 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
319 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; 319 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
320 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 320 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
index 459099e2515f..2d1e97d4264f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
@@ -60,8 +60,8 @@ nve0_identify(struct nouveau_device *device)
60 case 0xe4: 60 case 0xe4:
61 device->cname = "GK104"; 61 device->cname = "GK104";
62 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 62 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
63 device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; 63 device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
64 device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; 64 device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
65 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; 65 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
66 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; 66 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
67 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 67 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -93,8 +93,8 @@ nve0_identify(struct nouveau_device *device)
93 case 0xe7: 93 case 0xe7:
94 device->cname = "GK107"; 94 device->cname = "GK107";
95 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 95 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
96 device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; 96 device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
97 device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; 97 device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
98 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; 98 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
99 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; 99 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
100 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 100 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -126,8 +126,8 @@ nve0_identify(struct nouveau_device *device)
126 case 0xe6: 126 case 0xe6:
127 device->cname = "GK106"; 127 device->cname = "GK106";
128 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 128 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
129 device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; 129 device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
130 device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; 130 device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
131 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; 131 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
132 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; 132 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
133 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 133 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -176,8 +176,8 @@ nve0_identify(struct nouveau_device *device)
176 case 0xf0: 176 case 0xf0:
177 device->cname = "GK110"; 177 device->cname = "GK110";
178 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 178 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
179 device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; 179 device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
180 device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; 180 device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
181 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; 181 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
182 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; 182 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
183 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 183 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -209,8 +209,8 @@ nve0_identify(struct nouveau_device *device)
209 case 0xf1: 209 case 0xf1:
210 device->cname = "GK110B"; 210 device->cname = "GK110B";
211 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 211 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
212 device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; 212 device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
213 device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; 213 device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
214 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; 214 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
215 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; 215 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
216 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 216 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
@@ -242,8 +242,8 @@ nve0_identify(struct nouveau_device *device)
242 case 0x108: 242 case 0x108:
243 device->cname = "GK208"; 243 device->cname = "GK208";
244 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; 244 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
245 device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; 245 device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
246 device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; 246 device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
247 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; 247 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
248 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; 248 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
249 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 249 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/base.c b/drivers/gpu/drm/nouveau/core/engine/disp/base.c
index 7a5cae42834f..c41f656abe64 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/base.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/base.c
@@ -22,13 +22,87 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24 24
25#include <engine/disp.h> 25#include "priv.h"
26#include "outp.h"
27#include "conn.h"
28
29static int
30nouveau_disp_hpd_check(struct nouveau_event *event, u32 types, int index)
31{
32 struct nouveau_disp *disp = event->priv;
33 struct nvkm_output *outp;
34 list_for_each_entry(outp, &disp->outp, head) {
35 if (outp->conn->index == index) {
36 if (outp->conn->hpd.event)
37 return 0;
38 break;
39 }
40 }
41 return -ENOSYS;
42}
43
44int
45_nouveau_disp_fini(struct nouveau_object *object, bool suspend)
46{
47 struct nouveau_disp *disp = (void *)object;
48 struct nvkm_output *outp;
49 int ret;
50
51 list_for_each_entry(outp, &disp->outp, head) {
52 ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend);
53 if (ret && suspend)
54 goto fail_outp;
55 }
56
57 return nouveau_engine_fini(&disp->base, suspend);
58
59fail_outp:
60 list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
61 nv_ofuncs(outp)->init(nv_object(outp));
62 }
63
64 return ret;
65}
66
67int
68_nouveau_disp_init(struct nouveau_object *object)
69{
70 struct nouveau_disp *disp = (void *)object;
71 struct nvkm_output *outp;
72 int ret;
73
74 ret = nouveau_engine_init(&disp->base);
75 if (ret)
76 return ret;
77
78 list_for_each_entry(outp, &disp->outp, head) {
79 ret = nv_ofuncs(outp)->init(nv_object(outp));
80 if (ret)
81 goto fail_outp;
82 }
83
84 return ret;
85
86fail_outp:
87 list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
88 nv_ofuncs(outp)->fini(nv_object(outp), false);
89 }
90
91 return ret;
92}
26 93
27void 94void
28_nouveau_disp_dtor(struct nouveau_object *object) 95_nouveau_disp_dtor(struct nouveau_object *object)
29{ 96{
30 struct nouveau_disp *disp = (void *)object; 97 struct nouveau_disp *disp = (void *)object;
98 struct nvkm_output *outp, *outt;
99
31 nouveau_event_destroy(&disp->vblank); 100 nouveau_event_destroy(&disp->vblank);
101
102 list_for_each_entry_safe(outp, outt, &disp->outp, head) {
103 nouveau_object_ref(NULL, (struct nouveau_object **)&outp);
104 }
105
32 nouveau_engine_destroy(&disp->base); 106 nouveau_engine_destroy(&disp->base);
33} 107}
34 108
@@ -39,8 +113,15 @@ nouveau_disp_create_(struct nouveau_object *parent,
39 const char *intname, const char *extname, 113 const char *intname, const char *extname,
40 int length, void **pobject) 114 int length, void **pobject)
41{ 115{
116 struct nouveau_disp_impl *impl = (void *)oclass;
117 struct nouveau_bios *bios = nouveau_bios(parent);
42 struct nouveau_disp *disp; 118 struct nouveau_disp *disp;
43 int ret; 119 struct nouveau_oclass **sclass;
120 struct nouveau_object *object;
121 struct dcb_output dcbE;
122 u8 hpd = 0, ver, hdr;
123 u32 data;
124 int ret, i;
44 125
45 ret = nouveau_engine_create_(parent, engine, oclass, true, 126 ret = nouveau_engine_create_(parent, engine, oclass, true,
46 intname, extname, length, pobject); 127 intname, extname, length, pobject);
@@ -48,5 +129,42 @@ nouveau_disp_create_(struct nouveau_object *parent,
48 if (ret) 129 if (ret)
49 return ret; 130 return ret;
50 131
51 return nouveau_event_create(heads, &disp->vblank); 132 INIT_LIST_HEAD(&disp->outp);
133
134 /* create output objects for each display path in the vbios */
135 i = -1;
136 while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
137 if (dcbE.type == DCB_OUTPUT_UNUSED)
138 continue;
139 if (dcbE.type == DCB_OUTPUT_EOL)
140 break;
141 data = dcbE.location << 4 | dcbE.type;
142
143 oclass = nvkm_output_oclass;
144 sclass = impl->outp;
145 while (sclass && sclass[0]) {
146 if (sclass[0]->handle == data) {
147 oclass = sclass[0];
148 break;
149 }
150 sclass++;
151 }
152
153 nouveau_object_ctor(*pobject, *pobject, oclass,
154 &dcbE, i, &object);
155 hpd = max(hpd, (u8)(dcbE.connector + 1));
156 }
157
158 ret = nouveau_event_create(3, hpd, &disp->hpd);
159 if (ret)
160 return ret;
161
162 disp->hpd->priv = disp;
163 disp->hpd->check = nouveau_disp_hpd_check;
164
165 ret = nouveau_event_create(1, heads, &disp->vblank);
166 if (ret)
167 return ret;
168
169 return 0;
52} 170}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.c b/drivers/gpu/drm/nouveau/core/engine/disp/conn.c
new file mode 100644
index 000000000000..4ffbc70ecf5a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/conn.c
@@ -0,0 +1,172 @@
1/*
2 * Copyright 2014 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
27#include "conn.h"
28#include "outp.h"
29
30static void
31nvkm_connector_hpd_work(struct work_struct *w)
32{
33 struct nvkm_connector *conn = container_of(w, typeof(*conn), hpd.work);
34 struct nouveau_disp *disp = nouveau_disp(conn);
35 struct nouveau_gpio *gpio = nouveau_gpio(conn);
36 u32 send = NVKM_HPD_UNPLUG;
37 if (gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.event->index))
38 send = NVKM_HPD_PLUG;
39 nouveau_event_trigger(disp->hpd, send, conn->index);
40 nouveau_event_get(conn->hpd.event);
41}
42
43static int
44nvkm_connector_hpd(void *data, u32 type, int index)
45{
46 struct nvkm_connector *conn = data;
47 DBG("HPD: %d\n", type);
48 schedule_work(&conn->hpd.work);
49 return NVKM_EVENT_DROP;
50}
51
52int
53_nvkm_connector_fini(struct nouveau_object *object, bool suspend)
54{
55 struct nvkm_connector *conn = (void *)object;
56 if (conn->hpd.event)
57 nouveau_event_put(conn->hpd.event);
58 return nouveau_object_fini(&conn->base, suspend);
59}
60
61int
62_nvkm_connector_init(struct nouveau_object *object)
63{
64 struct nvkm_connector *conn = (void *)object;
65 int ret = nouveau_object_init(&conn->base);
66 if (ret == 0) {
67 if (conn->hpd.event)
68 nouveau_event_get(conn->hpd.event);
69 }
70 return ret;
71}
72
73void
74_nvkm_connector_dtor(struct nouveau_object *object)
75{
76 struct nvkm_connector *conn = (void *)object;
77 nouveau_event_ref(NULL, &conn->hpd.event);
78 nouveau_object_destroy(&conn->base);
79}
80
81int
82nvkm_connector_create_(struct nouveau_object *parent,
83 struct nouveau_object *engine,
84 struct nouveau_oclass *oclass,
85 struct nvbios_connE *info, int index,
86 int length, void **pobject)
87{
88 static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
89 struct nouveau_gpio *gpio = nouveau_gpio(parent);
90 struct nouveau_disp *disp = (void *)engine;
91 struct nvkm_connector *conn;
92 struct nvkm_output *outp;
93 struct dcb_gpio_func func;
94 int ret;
95
96 list_for_each_entry(outp, &disp->outp, head) {
97 if (outp->conn && outp->conn->index == index) {
98 atomic_inc(&nv_object(outp->conn)->refcount);
99 *pobject = outp->conn;
100 return 1;
101 }
102 }
103
104 ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
105 conn = *pobject;
106 if (ret)
107 return ret;
108
109 conn->info = *info;
110 conn->index = index;
111
112 DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n",
113 info->type, info->location, info->hpd, info->dp,
114 info->di, info->sr, info->lcdid);
115
116 if ((info->hpd = ffs(info->hpd))) {
117 if (--info->hpd >= ARRAY_SIZE(hpd)) {
118 ERR("hpd %02x unknown\n", info->hpd);
119 goto done;
120 }
121 info->hpd = hpd[info->hpd];
122
123 ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
124 if (ret) {
125 ERR("func %02x lookup failed, %d\n", info->hpd, ret);
126 goto done;
127 }
128
129 ret = nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED,
130 func.line, nvkm_connector_hpd,
131 conn, &conn->hpd.event);
132 if (ret) {
133 ERR("func %02x failed, %d\n", info->hpd, ret);
134 } else {
135 DBG("func %02x (HPD)\n", info->hpd);
136 }
137 }
138
139done:
140 INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work);
141 return 0;
142}
143
144int
145_nvkm_connector_ctor(struct nouveau_object *parent,
146 struct nouveau_object *engine,
147 struct nouveau_oclass *oclass, void *info, u32 index,
148 struct nouveau_object **pobject)
149{
150 struct nvkm_connector *conn;
151 int ret;
152
153 ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn);
154 *pobject = nv_object(conn);
155 if (ret)
156 return ret;
157
158 return 0;
159}
160
161struct nouveau_oclass *
162nvkm_connector_oclass = &(struct nvkm_connector_impl) {
163 .base = {
164 .handle = 0,
165 .ofuncs = &(struct nouveau_ofuncs) {
166 .ctor = _nvkm_connector_ctor,
167 .dtor = _nvkm_connector_dtor,
168 .init = _nvkm_connector_init,
169 .fini = _nvkm_connector_fini,
170 },
171 },
172}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.h b/drivers/gpu/drm/nouveau/core/engine/disp/conn.h
new file mode 100644
index 000000000000..035ebeacbb1c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/conn.h
@@ -0,0 +1,59 @@
1#ifndef __NVKM_DISP_CONN_H__
2#define __NVKM_DISP_CONN_H__
3
4#include "priv.h"
5
6struct nvkm_connector {
7 struct nouveau_object base;
8 struct list_head head;
9
10 struct nvbios_connE info;
11 int index;
12
13 struct {
14 struct nouveau_eventh *event;
15 struct work_struct work;
16 } hpd;
17};
18
19#define nvkm_connector_create(p,e,c,b,i,d) \
20 nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
21#define nvkm_connector_destroy(d) ({ \
22 struct nvkm_connector *disp = (d); \
23 _nvkm_connector_dtor(nv_object(disp)); \
24})
25#define nvkm_connector_init(d) ({ \
26 struct nvkm_connector *disp = (d); \
27 _nvkm_connector_init(nv_object(disp)); \
28})
29#define nvkm_connector_fini(d,s) ({ \
30 struct nvkm_connector *disp = (d); \
31 _nvkm_connector_fini(nv_object(disp), (s)); \
32})
33
34int nvkm_connector_create_(struct nouveau_object *, struct nouveau_object *,
35 struct nouveau_oclass *, struct nvbios_connE *,
36 int, int, void **);
37
38int _nvkm_connector_ctor(struct nouveau_object *, struct nouveau_object *,
39 struct nouveau_oclass *, void *, u32,
40 struct nouveau_object **);
41void _nvkm_connector_dtor(struct nouveau_object *);
42int _nvkm_connector_init(struct nouveau_object *);
43int _nvkm_connector_fini(struct nouveau_object *, bool);
44
45struct nvkm_connector_impl {
46 struct nouveau_oclass base;
47};
48
49#ifndef MSG
50#define MSG(l,f,a...) do { \
51 struct nvkm_connector *_conn = (void *)conn; \
52 nv_##l(nv_object(conn)->engine, "%02x:%02x%02x: "f, _conn->index, \
53 _conn->info.location, _conn->info.type, ##a); \
54} while(0)
55#define DBG(f,a...) MSG(debug, f, ##a)
56#define ERR(f,a...) MSG(error, f, ##a)
57#endif
58
59#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
index 13903533d7a2..39562d48101d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
@@ -30,42 +30,38 @@
30 30
31#include <engine/disp.h> 31#include <engine/disp.h>
32 32
33#include "dport.h" 33#include <core/class.h>
34 34
35#define DBG(fmt, args...) nv_debug(dp->disp, "DP:%04x:%04x: " fmt, \ 35#include "dport.h"
36 dp->outp->hasht, dp->outp->hashm, ##args) 36#include "outpdp.h"
37#define ERR(fmt, args...) nv_error(dp->disp, "DP:%04x:%04x: " fmt, \
38 dp->outp->hasht, dp->outp->hashm, ##args)
39 37
40/****************************************************************************** 38/******************************************************************************
41 * link training 39 * link training
42 *****************************************************************************/ 40 *****************************************************************************/
43struct dp_state { 41struct dp_state {
44 const struct nouveau_dp_func *func; 42 struct nvkm_output_dp *outp;
45 struct nouveau_disp *disp;
46 struct dcb_output *outp;
47 struct nvbios_dpout info;
48 u8 version;
49 struct nouveau_i2c_port *aux;
50 int head;
51 u8 dpcd[16];
52 int link_nr; 43 int link_nr;
53 u32 link_bw; 44 u32 link_bw;
54 u8 stat[6]; 45 u8 stat[6];
55 u8 conf[4]; 46 u8 conf[4];
47 bool pc2;
48 u8 pc2stat;
49 u8 pc2conf[2];
56}; 50};
57 51
58static int 52static int
59dp_set_link_config(struct dp_state *dp) 53dp_set_link_config(struct dp_state *dp)
60{ 54{
61 struct nouveau_disp *disp = dp->disp; 55 struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
56 struct nvkm_output_dp *outp = dp->outp;
57 struct nouveau_disp *disp = nouveau_disp(outp);
62 struct nouveau_bios *bios = nouveau_bios(disp); 58 struct nouveau_bios *bios = nouveau_bios(disp);
63 struct nvbios_init init = { 59 struct nvbios_init init = {
64 .subdev = nv_subdev(dp->disp), 60 .subdev = nv_subdev(disp),
65 .bios = bios, 61 .bios = bios,
66 .offset = 0x0000, 62 .offset = 0x0000,
67 .outp = dp->outp, 63 .outp = &outp->base.info,
68 .crtc = dp->head, 64 .crtc = -1,
69 .execute = 1, 65 .execute = 1,
70 }; 66 };
71 u32 lnkcmp; 67 u32 lnkcmp;
@@ -75,8 +71,8 @@ dp_set_link_config(struct dp_state *dp)
75 DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); 71 DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
76 72
77 /* set desired link configuration on the source */ 73 /* set desired link configuration on the source */
78 if ((lnkcmp = dp->info.lnkcmp)) { 74 if ((lnkcmp = dp->outp->info.lnkcmp)) {
79 if (dp->version < 0x30) { 75 if (outp->version < 0x30) {
80 while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp)) 76 while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp))
81 lnkcmp += 4; 77 lnkcmp += 4;
82 init.offset = nv_ro16(bios, lnkcmp + 2); 78 init.offset = nv_ro16(bios, lnkcmp + 2);
@@ -89,76 +85,112 @@ dp_set_link_config(struct dp_state *dp)
89 nvbios_exec(&init); 85 nvbios_exec(&init);
90 } 86 }
91 87
92 ret = dp->func->lnk_ctl(dp->disp, dp->outp, dp->head, 88 ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
93 dp->link_nr, dp->link_bw / 27000, 89 outp->dpcd[DPCD_RC02] &
94 dp->dpcd[DPCD_RC02] & 90 DPCD_RC02_ENHANCED_FRAME_CAP);
95 DPCD_RC02_ENHANCED_FRAME_CAP);
96 if (ret) { 91 if (ret) {
97 ERR("lnk_ctl failed with %d\n", ret); 92 if (ret < 0)
93 ERR("lnk_ctl failed with %d\n", ret);
98 return ret; 94 return ret;
99 } 95 }
100 96
97 impl->lnk_pwr(outp, dp->link_nr);
98
101 /* set desired link configuration on the sink */ 99 /* set desired link configuration on the sink */
102 sink[0] = dp->link_bw / 27000; 100 sink[0] = dp->link_bw / 27000;
103 sink[1] = dp->link_nr; 101 sink[1] = dp->link_nr;
104 if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) 102 if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
105 sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; 103 sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
106 104
107 return nv_wraux(dp->aux, DPCD_LC00, sink, 2); 105 return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2);
108} 106}
109 107
110static void 108static void
111dp_set_training_pattern(struct dp_state *dp, u8 pattern) 109dp_set_training_pattern(struct dp_state *dp, u8 pattern)
112{ 110{
111 struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
112 struct nvkm_output_dp *outp = dp->outp;
113 u8 sink_tp; 113 u8 sink_tp;
114 114
115 DBG("training pattern %d\n", pattern); 115 DBG("training pattern %d\n", pattern);
116 dp->func->pattern(dp->disp, dp->outp, dp->head, pattern); 116 impl->pattern(outp, pattern);
117 117
118 nv_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); 118 nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
119 sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; 119 sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
120 sink_tp |= pattern; 120 sink_tp |= pattern;
121 nv_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); 121 nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
122} 122}
123 123
124static int 124static int
125dp_link_train_commit(struct dp_state *dp) 125dp_link_train_commit(struct dp_state *dp, bool pc)
126{ 126{
127 int i; 127 struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
128 struct nvkm_output_dp *outp = dp->outp;
129 int ret, i;
128 130
129 for (i = 0; i < dp->link_nr; i++) { 131 for (i = 0; i < dp->link_nr; i++) {
130 u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; 132 u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
133 u8 lpc2 = (dp->pc2stat >> (i * 2)) & 0x3;
131 u8 lpre = (lane & 0x0c) >> 2; 134 u8 lpre = (lane & 0x0c) >> 2;
132 u8 lvsw = (lane & 0x03) >> 0; 135 u8 lvsw = (lane & 0x03) >> 0;
136 u8 hivs = 3 - lpre;
137 u8 hipe = 3;
138 u8 hipc = 3;
139
140 if (lpc2 >= hipc)
141 lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED;
142 if (lpre >= hipe) {
143 lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */
144 lvsw = hivs = 3 - (lpre & 3);
145 } else
146 if (lvsw >= hivs) {
147 lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED;
148 }
133 149
134 dp->conf[i] = (lpre << 3) | lvsw; 150 dp->conf[i] = (lpre << 3) | lvsw;
135 if (lvsw == 3) 151 dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
136 dp->conf[i] |= DPCD_LC03_MAX_SWING_REACHED;
137 if (lpre == 3)
138 dp->conf[i] |= DPCD_LC03_MAX_PRE_EMPHASIS_REACHED;
139 152
140 DBG("config lane %d %02x\n", i, dp->conf[i]); 153 DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2);
141 dp->func->drv_ctl(dp->disp, dp->outp, dp->head, i, lvsw, lpre); 154 impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3);
142 } 155 }
143 156
144 return nv_wraux(dp->aux, DPCD_LC03(0), dp->conf, 4); 157 ret = nv_wraux(outp->base.edid, DPCD_LC03(0), dp->conf, 4);
158 if (ret)
159 return ret;
160
161 if (pc) {
162 ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2);
163 if (ret)
164 return ret;
165 }
166
167 return 0;
145} 168}
146 169
147static int 170static int
148dp_link_train_update(struct dp_state *dp, u32 delay) 171dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
149{ 172{
173 struct nvkm_output_dp *outp = dp->outp;
150 int ret; 174 int ret;
151 175
152 if (dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) 176 if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
153 mdelay(dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); 177 mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
154 else 178 else
155 udelay(delay); 179 udelay(delay);
156 180
157 ret = nv_rdaux(dp->aux, DPCD_LS02, dp->stat, 6); 181 ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6);
158 if (ret) 182 if (ret)
159 return ret; 183 return ret;
160 184
161 DBG("status %6ph\n", dp->stat); 185 if (pc) {
186 ret = nv_rdaux(outp->base.edid, DPCD_LS0C, &dp->pc2stat, 1);
187 if (ret)
188 dp->pc2stat = 0x00;
189 DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat);
190 } else {
191 DBG("status %6ph\n", dp->stat);
192 }
193
162 return 0; 194 return 0;
163} 195}
164 196
@@ -172,8 +204,8 @@ dp_link_train_cr(struct dp_state *dp)
172 dp_set_training_pattern(dp, 1); 204 dp_set_training_pattern(dp, 1);
173 205
174 do { 206 do {
175 if (dp_link_train_commit(dp) || 207 if (dp_link_train_commit(dp, false) ||
176 dp_link_train_update(dp, 100)) 208 dp_link_train_update(dp, false, 100))
177 break; 209 break;
178 210
179 cr_done = true; 211 cr_done = true;
@@ -199,16 +231,17 @@ dp_link_train_cr(struct dp_state *dp)
199static int 231static int
200dp_link_train_eq(struct dp_state *dp) 232dp_link_train_eq(struct dp_state *dp)
201{ 233{
234 struct nvkm_output_dp *outp = dp->outp;
202 bool eq_done = false, cr_done = true; 235 bool eq_done = false, cr_done = true;
203 int tries = 0, i; 236 int tries = 0, i;
204 237
205 if (dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED) 238 if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED)
206 dp_set_training_pattern(dp, 3); 239 dp_set_training_pattern(dp, 3);
207 else 240 else
208 dp_set_training_pattern(dp, 2); 241 dp_set_training_pattern(dp, 2);
209 242
210 do { 243 do {
211 if (dp_link_train_update(dp, 400)) 244 if (dp_link_train_update(dp, dp->pc2, 400))
212 break; 245 break;
213 246
214 eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); 247 eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
@@ -221,7 +254,7 @@ dp_link_train_eq(struct dp_state *dp)
221 eq_done = false; 254 eq_done = false;
222 } 255 }
223 256
224 if (dp_link_train_commit(dp)) 257 if (dp_link_train_commit(dp, dp->pc2))
225 break; 258 break;
226 } while (!eq_done && cr_done && ++tries <= 5); 259 } while (!eq_done && cr_done && ++tries <= 5);
227 260
@@ -231,123 +264,109 @@ dp_link_train_eq(struct dp_state *dp)
231static void 264static void
232dp_link_train_init(struct dp_state *dp, bool spread) 265dp_link_train_init(struct dp_state *dp, bool spread)
233{ 266{
267 struct nvkm_output_dp *outp = dp->outp;
268 struct nouveau_disp *disp = nouveau_disp(outp);
269 struct nouveau_bios *bios = nouveau_bios(disp);
234 struct nvbios_init init = { 270 struct nvbios_init init = {
235 .subdev = nv_subdev(dp->disp), 271 .subdev = nv_subdev(disp),
236 .bios = nouveau_bios(dp->disp), 272 .bios = bios,
237 .outp = dp->outp, 273 .outp = &outp->base.info,
238 .crtc = dp->head, 274 .crtc = -1,
239 .execute = 1, 275 .execute = 1,
240 }; 276 };
241 277
242 /* set desired spread */ 278 /* set desired spread */
243 if (spread) 279 if (spread)
244 init.offset = dp->info.script[2]; 280 init.offset = outp->info.script[2];
245 else 281 else
246 init.offset = dp->info.script[3]; 282 init.offset = outp->info.script[3];
247 nvbios_exec(&init); 283 nvbios_exec(&init);
248 284
249 /* pre-train script */ 285 /* pre-train script */
250 init.offset = dp->info.script[0]; 286 init.offset = outp->info.script[0];
251 nvbios_exec(&init); 287 nvbios_exec(&init);
252} 288}
253 289
254static void 290static void
255dp_link_train_fini(struct dp_state *dp) 291dp_link_train_fini(struct dp_state *dp)
256{ 292{
293 struct nvkm_output_dp *outp = dp->outp;
294 struct nouveau_disp *disp = nouveau_disp(outp);
295 struct nouveau_bios *bios = nouveau_bios(disp);
257 struct nvbios_init init = { 296 struct nvbios_init init = {
258 .subdev = nv_subdev(dp->disp), 297 .subdev = nv_subdev(disp),
259 .bios = nouveau_bios(dp->disp), 298 .bios = bios,
260 .outp = dp->outp, 299 .outp = &outp->base.info,
261 .crtc = dp->head, 300 .crtc = -1,
262 .execute = 1, 301 .execute = 1,
263 }; 302 };
264 303
265 /* post-train script */ 304 /* post-train script */
266 init.offset = dp->info.script[1], 305 init.offset = outp->info.script[1],
267 nvbios_exec(&init); 306 nvbios_exec(&init);
268} 307}
269 308
270int 309static const struct dp_rates {
271nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, 310 u32 rate;
272 struct dcb_output *outp, int head, u32 datarate) 311 u8 bw;
312 u8 nr;
313} nouveau_dp_rates[] = {
314 { 2160000, 0x14, 4 },
315 { 1080000, 0x0a, 4 },
316 { 1080000, 0x14, 2 },
317 { 648000, 0x06, 4 },
318 { 540000, 0x0a, 2 },
319 { 540000, 0x14, 1 },
320 { 324000, 0x06, 2 },
321 { 270000, 0x0a, 1 },
322 { 162000, 0x06, 1 },
323 {}
324};
325
326void
327nouveau_dp_train(struct work_struct *w)
273{ 328{
274 struct nouveau_bios *bios = nouveau_bios(disp); 329 struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work);
275 struct nouveau_i2c *i2c = nouveau_i2c(disp); 330 struct nouveau_disp *disp = nouveau_disp(outp);
331 const struct dp_rates *cfg = nouveau_dp_rates;
276 struct dp_state _dp = { 332 struct dp_state _dp = {
277 .disp = disp,
278 .func = func,
279 .outp = outp, 333 .outp = outp,
280 .head = head,
281 }, *dp = &_dp; 334 }, *dp = &_dp;
282 const u32 bw_list[] = { 540000, 270000, 162000, 0 }; 335 u32 datarate = 0;
283 const u32 *link_bw = bw_list;
284 u8 hdr, cnt, len;
285 u32 data;
286 int ret; 336 int ret;
287 337
288 /* find the bios displayport data relevant to this output */
289 data = nvbios_dpout_match(bios, outp->hasht, outp->hashm, &dp->version,
290 &hdr, &cnt, &len, &dp->info);
291 if (!data) {
292 ERR("bios data not found\n");
293 return -EINVAL;
294 }
295
296 /* acquire the aux channel and fetch some info about the display */
297 if (outp->location)
298 dp->aux = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev));
299 else
300 dp->aux = i2c->find(i2c, NV_I2C_TYPE_DCBI2C(outp->i2c_index));
301 if (!dp->aux) {
302 ERR("no aux channel?!\n");
303 return -ENODEV;
304 }
305
306 ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd));
307 if (ret) {
308 /* it's possible the display has been unplugged before we
309 * get here. we still need to execute the full set of
310 * vbios scripts, and program the OR at a high enough
311 * frequency to satisfy the target mode. failure to do
312 * so results at best in an UPDATE hanging, and at worst
313 * with PDISP running away to join the circus.
314 */
315 dp->dpcd[1] = link_bw[0] / 27000;
316 dp->dpcd[2] = 4;
317 dp->dpcd[3] = 0x00;
318 ERR("failed to read DPCD\n");
319 }
320
321 /* bring capabilities within encoder limits */ 338 /* bring capabilities within encoder limits */
322 if (nv_oclass(disp)->handle < NV_ENGINE(DISP, 0x90)) 339 if (nv_mclass(disp) < NVD0_DISP_CLASS)
323 dp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; 340 outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
324 if ((dp->dpcd[2] & 0x1f) > dp->outp->dpconf.link_nr) { 341 if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
325 dp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; 342 outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
326 dp->dpcd[2] |= dp->outp->dpconf.link_nr; 343 outp->dpcd[2] |= outp->base.info.dpconf.link_nr;
344 }
345 if (outp->dpcd[1] > outp->base.info.dpconf.link_bw)
346 outp->dpcd[1] = outp->base.info.dpconf.link_bw;
347 dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED;
348
349 /* restrict link config to the lowest required rate, if requested */
350 if (datarate) {
351 datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */
352 while (cfg[1].rate >= datarate)
353 cfg++;
327 } 354 }
328 if (dp->dpcd[1] > dp->outp->dpconf.link_bw) 355 cfg--;
329 dp->dpcd[1] = dp->outp->dpconf.link_bw;
330 356
331 /* adjust required bandwidth for 8B/10B coding overhead */ 357 /* disable link interrupt handling during link training */
332 datarate = (datarate / 8) * 10; 358 nouveau_event_put(outp->irq);
333 359
334 /* enable down-spreading and execute pre-train script from vbios */ 360 /* enable down-spreading and execute pre-train script from vbios */
335 dp_link_train_init(dp, dp->dpcd[3] & 0x01); 361 dp_link_train_init(dp, outp->dpcd[3] & 0x01);
336 362
337 /* start off at highest link rate supported by encoder and display */ 363 while (ret = -EIO, (++cfg)->rate) {
338 while (*link_bw > (dp->dpcd[1] * 27000)) 364 /* select next configuration supported by encoder and sink */
339 link_bw++; 365 while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) ||
340 366 cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE]))
341 while ((ret = -EIO) && link_bw[0]) { 367 cfg++;
342 /* find minimum required lane count at this link rate */ 368 dp->link_bw = cfg->bw * 27000;
343 dp->link_nr = dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT; 369 dp->link_nr = cfg->nr;
344 while ((dp->link_nr >> 1) * link_bw[0] > datarate)
345 dp->link_nr >>= 1;
346
347 /* drop link rate to minimum with this lane count */
348 while ((link_bw[1] * dp->link_nr) > datarate)
349 link_bw++;
350 dp->link_bw = link_bw[0];
351 370
352 /* program selected link configuration */ 371 /* program selected link configuration */
353 ret = dp_set_link_config(dp); 372 ret = dp_set_link_config(dp);
@@ -364,17 +383,18 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
364 */ 383 */
365 break; 384 break;
366 } 385 }
367
368 /* retry at lower rate */
369 link_bw++;
370 } 386 }
371 387
372 /* finish link training */ 388 /* finish link training and execute post-train script from vbios */
373 dp_set_training_pattern(dp, 0); 389 dp_set_training_pattern(dp, 0);
374 if (ret < 0) 390 if (ret < 0)
375 ERR("link training failed\n"); 391 ERR("link training failed\n");
376 392
377 /* execute post-train script from vbios */
378 dp_link_train_fini(dp); 393 dp_link_train_fini(dp);
379 return (ret < 0) ? false : true; 394
395 /* signal completion and enable link interrupt handling */
396 DBG("training complete\n");
397 atomic_set(&outp->lt.done, 1);
398 wake_up(&outp->lt.wait);
399 nouveau_event_get(outp->irq);
380} 400}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h b/drivers/gpu/drm/nouveau/core/engine/disp/dport.h
index 43281c8e9e7b..5628d2d5ec71 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.h
@@ -13,8 +13,7 @@
13#define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e 13#define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e
14 14
15/* DPCD Link Configuration */ 15/* DPCD Link Configuration */
16#define DPCD_LC00 0x00100 16#define DPCD_LC00_LINK_BW_SET 0x00100
17#define DPCD_LC00_LINK_BW_SET 0xff
18#define DPCD_LC01 0x00101 17#define DPCD_LC01 0x00101
19#define DPCD_LC01_ENHANCED_FRAME_EN 0x80 18#define DPCD_LC01_ENHANCED_FRAME_EN 0x80
20#define DPCD_LC01_LANE_COUNT_SET 0x1f 19#define DPCD_LC01_LANE_COUNT_SET 0x1f
@@ -25,6 +24,16 @@
25#define DPCD_LC03_PRE_EMPHASIS_SET 0x18 24#define DPCD_LC03_PRE_EMPHASIS_SET 0x18
26#define DPCD_LC03_MAX_SWING_REACHED 0x04 25#define DPCD_LC03_MAX_SWING_REACHED 0x04
27#define DPCD_LC03_VOLTAGE_SWING_SET 0x03 26#define DPCD_LC03_VOLTAGE_SWING_SET 0x03
27#define DPCD_LC0F 0x0010f
28#define DPCD_LC0F_LANE1_MAX_POST_CURSOR2_REACHED 0x40
29#define DPCD_LC0F_LANE1_POST_CURSOR2_SET 0x30
30#define DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED 0x04
31#define DPCD_LC0F_LANE0_POST_CURSOR2_SET 0x03
32#define DPCD_LC10 0x00110
33#define DPCD_LC10_LANE3_MAX_POST_CURSOR2_REACHED 0x40
34#define DPCD_LC10_LANE3_POST_CURSOR2_SET 0x30
35#define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED 0x04
36#define DPCD_LC10_LANE2_POST_CURSOR2_SET 0x03
28 37
29/* DPCD Link/Sink Status */ 38/* DPCD Link/Sink Status */
30#define DPCD_LS02 0x00202 39#define DPCD_LS02 0x00202
@@ -55,24 +64,12 @@
55#define DPCD_LS07_LANE3_VOLTAGE_SWING 0x30 64#define DPCD_LS07_LANE3_VOLTAGE_SWING 0x30
56#define DPCD_LS07_LANE2_PRE_EMPHASIS 0x0c 65#define DPCD_LS07_LANE2_PRE_EMPHASIS 0x0c
57#define DPCD_LS07_LANE2_VOLTAGE_SWING 0x03 66#define DPCD_LS07_LANE2_VOLTAGE_SWING 0x03
67#define DPCD_LS0C 0x0020c
68#define DPCD_LS0C_LANE3_POST_CURSOR2 0xc0
69#define DPCD_LS0C_LANE2_POST_CURSOR2 0x30
70#define DPCD_LS0C_LANE1_POST_CURSOR2 0x0c
71#define DPCD_LS0C_LANE0_POST_CURSOR2 0x03
58 72
59struct nouveau_disp; 73void nouveau_dp_train(struct work_struct *);
60struct dcb_output;
61
62struct nouveau_dp_func {
63 int (*pattern)(struct nouveau_disp *, struct dcb_output *,
64 int head, int pattern);
65 int (*lnk_ctl)(struct nouveau_disp *, struct dcb_output *, int head,
66 int link_nr, int link_bw, bool enh_frame);
67 int (*drv_ctl)(struct nouveau_disp *, struct dcb_output *, int head,
68 int lane, int swing, int preem);
69};
70
71extern const struct nouveau_dp_func nv94_sor_dp_func;
72extern const struct nouveau_dp_func nvd0_sor_dp_func;
73extern const struct nouveau_dp_func nv50_pior_dp_func;
74
75int nouveau_dp_train(struct nouveau_disp *, const struct nouveau_dp_func *,
76 struct dcb_output *, int, u32);
77 74
78#endif 75#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
index cf6f59677b74..9fc7447fec90 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
@@ -81,7 +81,6 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
81 priv->sor.power = nv50_sor_power; 81 priv->sor.power = nv50_sor_power;
82 priv->sor.hda_eld = nvd0_hda_eld; 82 priv->sor.hda_eld = nvd0_hda_eld;
83 priv->sor.hdmi = nvd0_hdmi_ctrl; 83 priv->sor.hdmi = nvd0_hdmi_ctrl;
84 priv->sor.dp = &nvd0_sor_dp_func;
85 return 0; 84 return 0;
86} 85}
87 86
@@ -94,6 +93,7 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
94 .init = _nouveau_disp_init, 93 .init = _nouveau_disp_init,
95 .fini = _nouveau_disp_fini, 94 .fini = _nouveau_disp_fini,
96 }, 95 },
96 .base.outp = nvd0_disp_outp_sclass,
97 .mthd.core = &nve0_disp_mast_mthd_chan, 97 .mthd.core = &nve0_disp_mast_mthd_chan,
98 .mthd.base = &nvd0_disp_sync_mthd_chan, 98 .mthd.base = &nvd0_disp_sync_mthd_chan,
99 .mthd.ovly = &nve0_disp_ovly_mthd_chan, 99 .mthd.ovly = &nve0_disp_ovly_mthd_chan,
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
index 94a2cc69ec2c..a32666ed0c47 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
@@ -86,13 +86,13 @@ nv04_disp_sclass[] = {
86 ******************************************************************************/ 86 ******************************************************************************/
87 87
88static void 88static void
89nv04_disp_vblank_enable(struct nouveau_event *event, int head) 89nv04_disp_vblank_enable(struct nouveau_event *event, int type, int head)
90{ 90{
91 nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001); 91 nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001);
92} 92}
93 93
94static void 94static void
95nv04_disp_vblank_disable(struct nouveau_event *event, int head) 95nv04_disp_vblank_disable(struct nouveau_event *event, int type, int head)
96{ 96{
97 nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000); 97 nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000);
98} 98}
@@ -106,12 +106,12 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
106 u32 pvideo; 106 u32 pvideo;
107 107
108 if (crtc0 & 0x00000001) { 108 if (crtc0 & 0x00000001) {
109 nouveau_event_trigger(priv->base.vblank, 0); 109 nouveau_event_trigger(priv->base.vblank, 1, 0);
110 nv_wr32(priv, 0x600100, 0x00000001); 110 nv_wr32(priv, 0x600100, 0x00000001);
111 } 111 }
112 112
113 if (crtc1 & 0x00000001) { 113 if (crtc1 & 0x00000001) {
114 nouveau_event_trigger(priv->base.vblank, 1); 114 nouveau_event_trigger(priv->base.vblank, 1, 1);
115 nv_wr32(priv, 0x602100, 0x00000001); 115 nv_wr32(priv, 0x602100, 0x00000001);
116 } 116 }
117 117
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 9a0cab9c3adb..1e85f36c705f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -829,13 +829,13 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
829} 829}
830 830
831static void 831static void
832nv50_disp_base_vblank_enable(struct nouveau_event *event, int head) 832nv50_disp_base_vblank_enable(struct nouveau_event *event, int type, int head)
833{ 833{
834 nv_mask(event->priv, 0x61002c, (4 << head), (4 << head)); 834 nv_mask(event->priv, 0x61002c, (4 << head), (4 << head));
835} 835}
836 836
837static void 837static void
838nv50_disp_base_vblank_disable(struct nouveau_event *event, int head) 838nv50_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
839{ 839{
840 nv_mask(event->priv, 0x61002c, (4 << head), 0); 840 nv_mask(event->priv, 0x61002c, (4 << head), 0);
841} 841}
@@ -1114,19 +1114,20 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
1114 nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000); 1114 nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
1115} 1115}
1116 1116
1117static u16 1117static struct nvkm_output *
1118exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, 1118exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
1119 struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, 1119 u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
1120 struct nvbios_outp *info) 1120 struct nvbios_outp *info)
1121{ 1121{
1122 struct nouveau_bios *bios = nouveau_bios(priv); 1122 struct nouveau_bios *bios = nouveau_bios(priv);
1123 u16 mask, type, data; 1123 struct nvkm_output *outp;
1124 u16 mask, type;
1124 1125
1125 if (outp < 4) { 1126 if (or < 4) {
1126 type = DCB_OUTPUT_ANALOG; 1127 type = DCB_OUTPUT_ANALOG;
1127 mask = 0; 1128 mask = 0;
1128 } else 1129 } else
1129 if (outp < 8) { 1130 if (or < 8) {
1130 switch (ctrl & 0x00000f00) { 1131 switch (ctrl & 0x00000f00) {
1131 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; 1132 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
1132 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; 1133 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
@@ -1136,45 +1137,48 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
1136 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; 1137 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
1137 default: 1138 default:
1138 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); 1139 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
1139 return 0x0000; 1140 return NULL;
1140 } 1141 }
1141 outp -= 4; 1142 or -= 4;
1142 } else { 1143 } else {
1143 outp = outp - 8; 1144 or = or - 8;
1144 type = 0x0010; 1145 type = 0x0010;
1145 mask = 0; 1146 mask = 0;
1146 switch (ctrl & 0x00000f00) { 1147 switch (ctrl & 0x00000f00) {
1147 case 0x00000000: type |= priv->pior.type[outp]; break; 1148 case 0x00000000: type |= priv->pior.type[or]; break;
1148 default: 1149 default:
1149 nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl); 1150 nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
1150 return 0x0000; 1151 return NULL;
1151 } 1152 }
1152 } 1153 }
1153 1154
1154 mask = 0x00c0 & (mask << 6); 1155 mask = 0x00c0 & (mask << 6);
1155 mask |= 0x0001 << outp; 1156 mask |= 0x0001 << or;
1156 mask |= 0x0100 << head; 1157 mask |= 0x0100 << head;
1157 1158
1158 data = dcb_outp_match(bios, type, mask, ver, hdr, dcb); 1159 list_for_each_entry(outp, &priv->base.outp, head) {
1159 if (!data) 1160 if ((outp->info.hasht & 0xff) == type &&
1160 return 0x0000; 1161 (outp->info.hashm & mask) == mask) {
1161 1162 *data = nvbios_outp_match(bios, outp->info.hasht,
1162 /* off-chip encoders require matching the exact encoder type */ 1163 outp->info.hashm,
1163 if (dcb->location != 0) 1164 ver, hdr, cnt, len, info);
1164 type |= dcb->extdev << 8; 1165 if (!*data)
1166 return NULL;
1167 return outp;
1168 }
1169 }
1165 1170
1166 return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); 1171 return NULL;
1167} 1172}
1168 1173
1169static bool 1174static struct nvkm_output *
1170exec_script(struct nv50_disp_priv *priv, int head, int id) 1175exec_script(struct nv50_disp_priv *priv, int head, int id)
1171{ 1176{
1172 struct nouveau_bios *bios = nouveau_bios(priv); 1177 struct nouveau_bios *bios = nouveau_bios(priv);
1178 struct nvkm_output *outp;
1173 struct nvbios_outp info; 1179 struct nvbios_outp info;
1174 struct dcb_output dcb;
1175 u8 ver, hdr, cnt, len; 1180 u8 ver, hdr, cnt, len;
1176 u16 data; 1181 u32 data, ctrl = 0;
1177 u32 ctrl = 0x00000000;
1178 u32 reg; 1182 u32 reg;
1179 int i; 1183 int i;
1180 1184
@@ -1204,36 +1208,35 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
1204 } 1208 }
1205 1209
1206 if (!(ctrl & (1 << head))) 1210 if (!(ctrl & (1 << head)))
1207 return false; 1211 return NULL;
1208 i--; 1212 i--;
1209 1213
1210 data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); 1214 outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
1211 if (data) { 1215 if (outp) {
1212 struct nvbios_init init = { 1216 struct nvbios_init init = {
1213 .subdev = nv_subdev(priv), 1217 .subdev = nv_subdev(priv),
1214 .bios = bios, 1218 .bios = bios,
1215 .offset = info.script[id], 1219 .offset = info.script[id],
1216 .outp = &dcb, 1220 .outp = &outp->info,
1217 .crtc = head, 1221 .crtc = head,
1218 .execute = 1, 1222 .execute = 1,
1219 }; 1223 };
1220 1224
1221 return nvbios_exec(&init) == 0; 1225 nvbios_exec(&init);
1222 } 1226 }
1223 1227
1224 return false; 1228 return outp;
1225} 1229}
1226 1230
1227static u32 1231static struct nvkm_output *
1228exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, 1232exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
1229 struct dcb_output *outp)
1230{ 1233{
1231 struct nouveau_bios *bios = nouveau_bios(priv); 1234 struct nouveau_bios *bios = nouveau_bios(priv);
1235 struct nvkm_output *outp;
1232 struct nvbios_outp info1; 1236 struct nvbios_outp info1;
1233 struct nvbios_ocfg info2; 1237 struct nvbios_ocfg info2;
1234 u8 ver, hdr, cnt, len; 1238 u8 ver, hdr, cnt, len;
1235 u32 ctrl = 0x00000000; 1239 u32 data, ctrl = 0;
1236 u32 data, conf = ~0;
1237 u32 reg; 1240 u32 reg;
1238 int i; 1241 int i;
1239 1242
@@ -1263,37 +1266,37 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
1263 } 1266 }
1264 1267
1265 if (!(ctrl & (1 << head))) 1268 if (!(ctrl & (1 << head)))
1266 return conf; 1269 return NULL;
1267 i--; 1270 i--;
1268 1271
1269 data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); 1272 outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
1270 if (!data) 1273 if (!data)
1271 return conf; 1274 return NULL;
1272 1275
1273 if (outp->location == 0) { 1276 if (outp->info.location == 0) {
1274 switch (outp->type) { 1277 switch (outp->info.type) {
1275 case DCB_OUTPUT_TMDS: 1278 case DCB_OUTPUT_TMDS:
1276 conf = (ctrl & 0x00000f00) >> 8; 1279 *conf = (ctrl & 0x00000f00) >> 8;
1277 if (pclk >= 165000) 1280 if (pclk >= 165000)
1278 conf |= 0x0100; 1281 *conf |= 0x0100;
1279 break; 1282 break;
1280 case DCB_OUTPUT_LVDS: 1283 case DCB_OUTPUT_LVDS:
1281 conf = priv->sor.lvdsconf; 1284 *conf = priv->sor.lvdsconf;
1282 break; 1285 break;
1283 case DCB_OUTPUT_DP: 1286 case DCB_OUTPUT_DP:
1284 conf = (ctrl & 0x00000f00) >> 8; 1287 *conf = (ctrl & 0x00000f00) >> 8;
1285 break; 1288 break;
1286 case DCB_OUTPUT_ANALOG: 1289 case DCB_OUTPUT_ANALOG:
1287 default: 1290 default:
1288 conf = 0x00ff; 1291 *conf = 0x00ff;
1289 break; 1292 break;
1290 } 1293 }
1291 } else { 1294 } else {
1292 conf = (ctrl & 0x00000f00) >> 8; 1295 *conf = (ctrl & 0x00000f00) >> 8;
1293 pclk = pclk / 2; 1296 pclk = pclk / 2;
1294 } 1297 }
1295 1298
1296 data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); 1299 data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
1297 if (data && id < 0xff) { 1300 if (data && id < 0xff) {
1298 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); 1301 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
1299 if (data) { 1302 if (data) {
@@ -1301,7 +1304,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
1301 .subdev = nv_subdev(priv), 1304 .subdev = nv_subdev(priv),
1302 .bios = bios, 1305 .bios = bios,
1303 .offset = data, 1306 .offset = data,
1304 .outp = outp, 1307 .outp = &outp->info,
1305 .crtc = head, 1308 .crtc = head,
1306 .execute = 1, 1309 .execute = 1,
1307 }; 1310 };
@@ -1310,7 +1313,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
1310 } 1313 }
1311 } 1314 }
1312 1315
1313 return conf; 1316 return outp;
1314} 1317}
1315 1318
1316static void 1319static void
@@ -1322,7 +1325,35 @@ nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
1322static void 1325static void
1323nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) 1326nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
1324{ 1327{
1325 exec_script(priv, head, 2); 1328 struct nvkm_output *outp = exec_script(priv, head, 2);
1329
1330 /* the binary driver does this outside of the supervisor handling
1331 * (after the third supervisor from a detach). we (currently?)
1332 * allow both detach/attach to happen in the same set of
1333 * supervisor interrupts, so it would make sense to execute this
1334 * (full power down?) script after all the detach phases of the
1335 * supervisor handling. like with training if needed from the
1336 * second supervisor, nvidia doesn't do this, so who knows if it's
1337 * entirely safe, but it does appear to work..
1338 *
1339 * without this script being run, on some configurations i've
1340 * seen, switching from DP to TMDS on a DP connector may result
1341 * in a blank screen (SOR_PWR off/on can restore it)
1342 */
1343 if (outp && outp->info.type == DCB_OUTPUT_DP) {
1344 struct nvkm_output_dp *outpdp = (void *)outp;
1345 struct nvbios_init init = {
1346 .subdev = nv_subdev(priv),
1347 .bios = nouveau_bios(priv),
1348 .outp = &outp->info,
1349 .crtc = head,
1350 .offset = outpdp->info.script[4],
1351 .execute = 1,
1352 };
1353
1354 nvbios_exec(&init);
1355 atomic_set(&outpdp->lt.done, 0);
1356 }
1326} 1357}
1327 1358
1328static void 1359static void
@@ -1444,56 +1475,83 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
1444static void 1475static void
1445nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) 1476nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
1446{ 1477{
1447 struct dcb_output outp; 1478 struct nvkm_output *outp;
1448 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; 1479 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1449 u32 hval, hreg = 0x614200 + (head * 0x800); 1480 u32 hval, hreg = 0x614200 + (head * 0x800);
1450 u32 oval, oreg; 1481 u32 oval, oreg;
1451 u32 mask; 1482 u32 mask, conf;
1452 u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp);
1453 if (conf != ~0) {
1454 if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
1455 u32 soff = (ffs(outp.or) - 1) * 0x08;
1456 u32 ctrl = nv_rd32(priv, 0x610794 + soff);
1457 u32 datarate;
1458
1459 switch ((ctrl & 0x000f0000) >> 16) {
1460 case 6: datarate = pclk * 30 / 8; break;
1461 case 5: datarate = pclk * 24 / 8; break;
1462 case 2:
1463 default:
1464 datarate = pclk * 18 / 8;
1465 break;
1466 }
1467 1483
1468 nouveau_dp_train(&priv->base, priv->sor.dp, 1484 outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
1469 &outp, head, datarate); 1485 if (!outp)
1470 } 1486 return;
1487
1488 /* we allow both encoder attach and detach operations to occur
1489 * within a single supervisor (ie. modeset) sequence. the
1490 * encoder detach scripts quite often switch off power to the
1491 * lanes, which requires the link to be re-trained.
1492 *
1493 * this is not generally an issue as the sink "must" (heh)
1494 * signal an irq when it's lost sync so the driver can
1495 * re-train.
1496 *
1497 * however, on some boards, if one does not configure at least
1498 * the gpu side of the link *before* attaching, then various
1499 * things can go horribly wrong (PDISP disappearing from mmio,
1500 * third supervisor never happens, etc).
1501 *
1502 * the solution is simply to retrain here, if necessary. last
1503 * i checked, the binary driver userspace does not appear to
1504 * trigger this situation (it forces an UPDATE between steps).
1505 */
1506 if (outp->info.type == DCB_OUTPUT_DP) {
1507 u32 soff = (ffs(outp->info.or) - 1) * 0x08;
1508 u32 ctrl, datarate;
1471 1509
1472 exec_clkcmp(priv, head, 0, pclk, &outp); 1510 if (outp->info.location == 0) {
1473 1511 ctrl = nv_rd32(priv, 0x610794 + soff);
1474 if (!outp.location && outp.type == DCB_OUTPUT_ANALOG) { 1512 soff = 1;
1475 oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800;
1476 oval = 0x00000000;
1477 hval = 0x00000000;
1478 mask = 0xffffffff;
1479 } else
1480 if (!outp.location) {
1481 if (outp.type == DCB_OUTPUT_DP)
1482 nv50_disp_intr_unk20_2_dp(priv, &outp, pclk);
1483 oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800;
1484 oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
1485 hval = 0x00000000;
1486 mask = 0x00000707;
1487 } else { 1513 } else {
1488 oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800; 1514 ctrl = nv_rd32(priv, 0x610b80 + soff);
1489 oval = 0x00000001; 1515 soff = 2;
1490 hval = 0x00000001;
1491 mask = 0x00000707;
1492 } 1516 }
1493 1517
1494 nv_mask(priv, hreg, 0x0000000f, hval); 1518 switch ((ctrl & 0x000f0000) >> 16) {
1495 nv_mask(priv, oreg, mask, oval); 1519 case 6: datarate = pclk * 30 / 8; break;
1520 case 5: datarate = pclk * 24 / 8; break;
1521 case 2:
1522 default:
1523 datarate = pclk * 18 / 8;
1524 break;
1525 }
1526
1527 if (nvkm_output_dp_train(outp, datarate / soff, true))
1528 ERR("link not trained before attach\n");
1496 } 1529 }
1530
1531 exec_clkcmp(priv, head, 0, pclk, &conf);
1532
1533 if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
1534 oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
1535 oval = 0x00000000;
1536 hval = 0x00000000;
1537 mask = 0xffffffff;
1538 } else
1539 if (!outp->info.location) {
1540 if (outp->info.type == DCB_OUTPUT_DP)
1541 nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk);
1542 oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
1543 oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
1544 hval = 0x00000000;
1545 mask = 0x00000707;
1546 } else {
1547 oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
1548 oval = 0x00000001;
1549 hval = 0x00000001;
1550 mask = 0x00000707;
1551 }
1552
1553 nv_mask(priv, hreg, 0x0000000f, hval);
1554 nv_mask(priv, oreg, mask, oval);
1497} 1555}
1498 1556
1499/* If programming a TMDS output on a SOR that can also be configured for 1557/* If programming a TMDS output on a SOR that can also be configured for
@@ -1521,30 +1579,16 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp
1521static void 1579static void
1522nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head) 1580nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
1523{ 1581{
1524 struct dcb_output outp; 1582 struct nvkm_output *outp;
1525 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; 1583 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1526 if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) { 1584 u32 conf;
1527 if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS)
1528 nv50_disp_intr_unk40_0_tmds(priv, &outp);
1529 else
1530 if (outp.location == 1 && outp.type == DCB_OUTPUT_DP) {
1531 u32 soff = (ffs(outp.or) - 1) * 0x08;
1532 u32 ctrl = nv_rd32(priv, 0x610b84 + soff);
1533 u32 datarate;
1534
1535 switch ((ctrl & 0x000f0000) >> 16) {
1536 case 6: datarate = pclk * 30 / 8; break;
1537 case 5: datarate = pclk * 24 / 8; break;
1538 case 2:
1539 default:
1540 datarate = pclk * 18 / 8;
1541 break;
1542 }
1543 1585
1544 nouveau_dp_train(&priv->base, priv->pior.dp, 1586 outp = exec_clkcmp(priv, head, 1, pclk, &conf);
1545 &outp, head, datarate); 1587 if (!outp)
1546 } 1588 return;
1547 } 1589
1590 if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
1591 nv50_disp_intr_unk40_0_tmds(priv, &outp->info);
1548} 1592}
1549 1593
1550void 1594void
@@ -1610,13 +1654,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
1610 } 1654 }
1611 1655
1612 if (intr1 & 0x00000004) { 1656 if (intr1 & 0x00000004) {
1613 nouveau_event_trigger(priv->base.vblank, 0); 1657 nouveau_event_trigger(priv->base.vblank, 1, 0);
1614 nv_wr32(priv, 0x610024, 0x00000004); 1658 nv_wr32(priv, 0x610024, 0x00000004);
1615 intr1 &= ~0x00000004; 1659 intr1 &= ~0x00000004;
1616 } 1660 }
1617 1661
1618 if (intr1 & 0x00000008) { 1662 if (intr1 & 0x00000008) {
1619 nouveau_event_trigger(priv->base.vblank, 1); 1663 nouveau_event_trigger(priv->base.vblank, 1, 1);
1620 nv_wr32(priv, 0x610024, 0x00000008); 1664 nv_wr32(priv, 0x610024, 0x00000008);
1621 intr1 &= ~0x00000008; 1665 intr1 &= ~0x00000008;
1622 } 1666 }
@@ -1656,11 +1700,16 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
1656 priv->dac.sense = nv50_dac_sense; 1700 priv->dac.sense = nv50_dac_sense;
1657 priv->sor.power = nv50_sor_power; 1701 priv->sor.power = nv50_sor_power;
1658 priv->pior.power = nv50_pior_power; 1702 priv->pior.power = nv50_pior_power;
1659 priv->pior.dp = &nv50_pior_dp_func;
1660 return 0; 1703 return 0;
1661} 1704}
1662 1705
1663struct nouveau_oclass * 1706struct nouveau_oclass *
1707nv50_disp_outp_sclass[] = {
1708 &nv50_pior_dp_impl.base.base,
1709 NULL
1710};
1711
1712struct nouveau_oclass *
1664nv50_disp_oclass = &(struct nv50_disp_impl) { 1713nv50_disp_oclass = &(struct nv50_disp_impl) {
1665 .base.base.handle = NV_ENGINE(DISP, 0x50), 1714 .base.base.handle = NV_ENGINE(DISP, 0x50),
1666 .base.base.ofuncs = &(struct nouveau_ofuncs) { 1715 .base.base.ofuncs = &(struct nouveau_ofuncs) {
@@ -1669,6 +1718,7 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
1669 .init = _nouveau_disp_init, 1718 .init = _nouveau_disp_init,
1670 .fini = _nouveau_disp_fini, 1719 .fini = _nouveau_disp_fini,
1671 }, 1720 },
1721 .base.outp = nv50_disp_outp_sclass,
1672 .mthd.core = &nv50_disp_mast_mthd_chan, 1722 .mthd.core = &nv50_disp_mast_mthd_chan,
1673 .mthd.base = &nv50_disp_sync_mthd_chan, 1723 .mthd.base = &nv50_disp_sync_mthd_chan,
1674 .mthd.ovly = &nv50_disp_ovly_mthd_chan, 1724 .mthd.ovly = &nv50_disp_ovly_mthd_chan,
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
index 48d59db47f0d..1a886472b6f5 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
@@ -11,6 +11,8 @@
11 11
12#include "dport.h" 12#include "dport.h"
13#include "priv.h" 13#include "priv.h"
14#include "outp.h"
15#include "outpdp.h"
14 16
15struct nv50_disp_impl { 17struct nv50_disp_impl {
16 struct nouveau_disp_impl base; 18 struct nouveau_disp_impl base;
@@ -43,13 +45,11 @@ struct nv50_disp_priv {
43 int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32); 45 int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32);
44 int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32); 46 int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32);
45 u32 lvdsconf; 47 u32 lvdsconf;
46 const struct nouveau_dp_func *dp;
47 } sor; 48 } sor;
48 struct { 49 struct {
49 int nr; 50 int nr;
50 int (*power)(struct nv50_disp_priv *, int ext, u32 data); 51 int (*power)(struct nv50_disp_priv *, int ext, u32 data);
51 u8 type[3]; 52 u8 type[3];
52 const struct nouveau_dp_func *dp;
53 } pior; 53 } pior;
54}; 54};
55 55
@@ -199,4 +199,14 @@ void nvd0_disp_intr(struct nouveau_subdev *);
199extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan; 199extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan;
200extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan; 200extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan;
201 201
202extern struct nvkm_output_dp_impl nv50_pior_dp_impl;
203extern struct nouveau_oclass *nv50_disp_outp_sclass[];
204
205extern struct nvkm_output_dp_impl nv94_sor_dp_impl;
206int nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int);
207extern struct nouveau_oclass *nv94_disp_outp_sclass[];
208
209extern struct nvkm_output_dp_impl nvd0_sor_dp_impl;
210extern struct nouveau_oclass *nvd0_disp_outp_sclass[];
211
202#endif 212#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
index 98c5b19bc2b0..1cc62e434683 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
@@ -264,7 +264,6 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
264 priv->sor.power = nv50_sor_power; 264 priv->sor.power = nv50_sor_power;
265 priv->sor.hdmi = nv84_hdmi_ctrl; 265 priv->sor.hdmi = nv84_hdmi_ctrl;
266 priv->pior.power = nv50_pior_power; 266 priv->pior.power = nv50_pior_power;
267 priv->pior.dp = &nv50_pior_dp_func;
268 return 0; 267 return 0;
269} 268}
270 269
@@ -277,6 +276,7 @@ nv84_disp_oclass = &(struct nv50_disp_impl) {
277 .init = _nouveau_disp_init, 276 .init = _nouveau_disp_init,
278 .fini = _nouveau_disp_fini, 277 .fini = _nouveau_disp_fini,
279 }, 278 },
279 .base.outp = nv50_disp_outp_sclass,
280 .mthd.core = &nv84_disp_mast_mthd_chan, 280 .mthd.core = &nv84_disp_mast_mthd_chan,
281 .mthd.base = &nv84_disp_sync_mthd_chan, 281 .mthd.base = &nv84_disp_sync_mthd_chan,
282 .mthd.ovly = &nv84_disp_ovly_mthd_chan, 282 .mthd.ovly = &nv84_disp_ovly_mthd_chan,
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
index 6844061c7e04..4f718a9f5aef 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
@@ -77,6 +77,7 @@ nv94_disp_base_omthds[] = {
77 { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, 77 { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
78 { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, 78 { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
79 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, 79 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
80 { SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
80 { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, 81 { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
81 { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, 82 { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
82 { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, 83 { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
@@ -122,13 +123,18 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
122 priv->dac.sense = nv50_dac_sense; 123 priv->dac.sense = nv50_dac_sense;
123 priv->sor.power = nv50_sor_power; 124 priv->sor.power = nv50_sor_power;
124 priv->sor.hdmi = nv84_hdmi_ctrl; 125 priv->sor.hdmi = nv84_hdmi_ctrl;
125 priv->sor.dp = &nv94_sor_dp_func;
126 priv->pior.power = nv50_pior_power; 126 priv->pior.power = nv50_pior_power;
127 priv->pior.dp = &nv50_pior_dp_func;
128 return 0; 127 return 0;
129} 128}
130 129
131struct nouveau_oclass * 130struct nouveau_oclass *
131nv94_disp_outp_sclass[] = {
132 &nv50_pior_dp_impl.base.base,
133 &nv94_sor_dp_impl.base.base,
134 NULL
135};
136
137struct nouveau_oclass *
132nv94_disp_oclass = &(struct nv50_disp_impl) { 138nv94_disp_oclass = &(struct nv50_disp_impl) {
133 .base.base.handle = NV_ENGINE(DISP, 0x88), 139 .base.base.handle = NV_ENGINE(DISP, 0x88),
134 .base.base.ofuncs = &(struct nouveau_ofuncs) { 140 .base.base.ofuncs = &(struct nouveau_ofuncs) {
@@ -137,6 +143,7 @@ nv94_disp_oclass = &(struct nv50_disp_impl) {
137 .init = _nouveau_disp_init, 143 .init = _nouveau_disp_init,
138 .fini = _nouveau_disp_fini, 144 .fini = _nouveau_disp_fini,
139 }, 145 },
146 .base.outp = nv94_disp_outp_sclass,
140 .mthd.core = &nv94_disp_mast_mthd_chan, 147 .mthd.core = &nv94_disp_mast_mthd_chan,
141 .mthd.base = &nv84_disp_sync_mthd_chan, 148 .mthd.base = &nv84_disp_sync_mthd_chan,
142 .mthd.ovly = &nv84_disp_ovly_mthd_chan, 149 .mthd.ovly = &nv84_disp_ovly_mthd_chan,
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
index 88c96241c02a..6237a9a36f70 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
@@ -126,7 +126,6 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
126 priv->sor.power = nv50_sor_power; 126 priv->sor.power = nv50_sor_power;
127 priv->sor.hdmi = nv84_hdmi_ctrl; 127 priv->sor.hdmi = nv84_hdmi_ctrl;
128 priv->pior.power = nv50_pior_power; 128 priv->pior.power = nv50_pior_power;
129 priv->pior.dp = &nv50_pior_dp_func;
130 return 0; 129 return 0;
131} 130}
132 131
@@ -139,6 +138,7 @@ nva0_disp_oclass = &(struct nv50_disp_impl) {
139 .init = _nouveau_disp_init, 138 .init = _nouveau_disp_init,
140 .fini = _nouveau_disp_fini, 139 .fini = _nouveau_disp_fini,
141 }, 140 },
141 .base.outp = nv50_disp_outp_sclass,
142 .mthd.core = &nv84_disp_mast_mthd_chan, 142 .mthd.core = &nv84_disp_mast_mthd_chan,
143 .mthd.base = &nv84_disp_sync_mthd_chan, 143 .mthd.base = &nv84_disp_sync_mthd_chan,
144 .mthd.ovly = &nva0_disp_ovly_mthd_chan, 144 .mthd.ovly = &nva0_disp_ovly_mthd_chan,
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
index 46cb2ce0e82a..019124d4782b 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
@@ -50,6 +50,7 @@ nva3_disp_base_omthds[] = {
50 { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, 50 { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd },
51 { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, 51 { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
52 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, 52 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
53 { SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
53 { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, 54 { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
54 { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, 55 { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
55 { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, 56 { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
@@ -96,9 +97,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
96 priv->sor.power = nv50_sor_power; 97 priv->sor.power = nv50_sor_power;
97 priv->sor.hda_eld = nva3_hda_eld; 98 priv->sor.hda_eld = nva3_hda_eld;
98 priv->sor.hdmi = nva3_hdmi_ctrl; 99 priv->sor.hdmi = nva3_hdmi_ctrl;
99 priv->sor.dp = &nv94_sor_dp_func;
100 priv->pior.power = nv50_pior_power; 100 priv->pior.power = nv50_pior_power;
101 priv->pior.dp = &nv50_pior_dp_func;
102 return 0; 101 return 0;
103} 102}
104 103
@@ -111,6 +110,7 @@ nva3_disp_oclass = &(struct nv50_disp_impl) {
111 .init = _nouveau_disp_init, 110 .init = _nouveau_disp_init,
112 .fini = _nouveau_disp_fini, 111 .fini = _nouveau_disp_fini,
113 }, 112 },
113 .base.outp = nv94_disp_outp_sclass,
114 .mthd.core = &nv94_disp_mast_mthd_chan, 114 .mthd.core = &nv94_disp_mast_mthd_chan,
115 .mthd.base = &nv84_disp_sync_mthd_chan, 115 .mthd.base = &nv84_disp_sync_mthd_chan,
116 .mthd.ovly = &nv84_disp_ovly_mthd_chan, 116 .mthd.ovly = &nv84_disp_ovly_mthd_chan,
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
index 876de9ac3793..48aa38a87e3f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -748,13 +748,13 @@ nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
748} 748}
749 749
750static void 750static void
751nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head) 751nvd0_disp_base_vblank_enable(struct nouveau_event *event, int type, int head)
752{ 752{
753 nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); 753 nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
754} 754}
755 755
756static void 756static void
757nvd0_disp_base_vblank_disable(struct nouveau_event *event, int head) 757nvd0_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
758{ 758{
759 nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); 759 nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
760} 760}
@@ -887,6 +887,7 @@ nvd0_disp_base_omthds[] = {
887 { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, 887 { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd },
888 { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, 888 { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
889 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, 889 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
890 { SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
890 { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, 891 { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
891 { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, 892 { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
892 { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, 893 { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
@@ -915,19 +916,20 @@ nvd0_disp_sclass[] = {
915 * Display engine implementation 916 * Display engine implementation
916 ******************************************************************************/ 917 ******************************************************************************/
917 918
918static u16 919static struct nvkm_output *
919exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, 920exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
920 struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, 921 u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
921 struct nvbios_outp *info) 922 struct nvbios_outp *info)
922{ 923{
923 struct nouveau_bios *bios = nouveau_bios(priv); 924 struct nouveau_bios *bios = nouveau_bios(priv);
924 u16 mask, type, data; 925 struct nvkm_output *outp;
926 u16 mask, type;
925 927
926 if (outp < 4) { 928 if (or < 4) {
927 type = DCB_OUTPUT_ANALOG; 929 type = DCB_OUTPUT_ANALOG;
928 mask = 0; 930 mask = 0;
929 } else { 931 } else {
930 outp -= 4; 932 or -= 4;
931 switch (ctrl & 0x00000f00) { 933 switch (ctrl & 0x00000f00) {
932 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; 934 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
933 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; 935 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
@@ -939,101 +941,106 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
939 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); 941 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
940 return 0x0000; 942 return 0x0000;
941 } 943 }
942 dcb->sorconf.link = mask;
943 } 944 }
944 945
945 mask = 0x00c0 & (mask << 6); 946 mask = 0x00c0 & (mask << 6);
946 mask |= 0x0001 << outp; 947 mask |= 0x0001 << or;
947 mask |= 0x0100 << head; 948 mask |= 0x0100 << head;
948 949
949 data = dcb_outp_match(bios, type, mask, ver, hdr, dcb); 950 list_for_each_entry(outp, &priv->base.outp, head) {
950 if (!data) 951 if ((outp->info.hasht & 0xff) == type &&
951 return 0x0000; 952 (outp->info.hashm & mask) == mask) {
953 *data = nvbios_outp_match(bios, outp->info.hasht,
954 outp->info.hashm,
955 ver, hdr, cnt, len, info);
956 if (!*data)
957 return NULL;
958 return outp;
959 }
960 }
952 961
953 return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); 962 return NULL;
954} 963}
955 964
956static bool 965static struct nvkm_output *
957exec_script(struct nv50_disp_priv *priv, int head, int id) 966exec_script(struct nv50_disp_priv *priv, int head, int id)
958{ 967{
959 struct nouveau_bios *bios = nouveau_bios(priv); 968 struct nouveau_bios *bios = nouveau_bios(priv);
969 struct nvkm_output *outp;
960 struct nvbios_outp info; 970 struct nvbios_outp info;
961 struct dcb_output dcb;
962 u8 ver, hdr, cnt, len; 971 u8 ver, hdr, cnt, len;
963 u32 ctrl = 0x00000000; 972 u32 data, ctrl = 0;
964 u16 data; 973 int or;
965 int outp;
966 974
967 for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { 975 for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
968 ctrl = nv_rd32(priv, 0x640180 + (outp * 0x20)); 976 ctrl = nv_rd32(priv, 0x640180 + (or * 0x20));
969 if (ctrl & (1 << head)) 977 if (ctrl & (1 << head))
970 break; 978 break;
971 } 979 }
972 980
973 if (outp == 8) 981 if (or == 8)
974 return false; 982 return NULL;
975 983
976 data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); 984 outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
977 if (data) { 985 if (outp) {
978 struct nvbios_init init = { 986 struct nvbios_init init = {
979 .subdev = nv_subdev(priv), 987 .subdev = nv_subdev(priv),
980 .bios = bios, 988 .bios = bios,
981 .offset = info.script[id], 989 .offset = info.script[id],
982 .outp = &dcb, 990 .outp = &outp->info,
983 .crtc = head, 991 .crtc = head,
984 .execute = 1, 992 .execute = 1,
985 }; 993 };
986 994
987 return nvbios_exec(&init) == 0; 995 nvbios_exec(&init);
988 } 996 }
989 997
990 return false; 998 return outp;
991} 999}
992 1000
993static u32 1001static struct nvkm_output *
994exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, 1002exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
995 u32 pclk, struct dcb_output *dcb)
996{ 1003{
997 struct nouveau_bios *bios = nouveau_bios(priv); 1004 struct nouveau_bios *bios = nouveau_bios(priv);
1005 struct nvkm_output *outp;
998 struct nvbios_outp info1; 1006 struct nvbios_outp info1;
999 struct nvbios_ocfg info2; 1007 struct nvbios_ocfg info2;
1000 u8 ver, hdr, cnt, len; 1008 u8 ver, hdr, cnt, len;
1001 u32 ctrl = 0x00000000; 1009 u32 data, ctrl = 0;
1002 u32 data, conf = ~0; 1010 int or;
1003 int outp;
1004 1011
1005 for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { 1012 for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
1006 ctrl = nv_rd32(priv, 0x660180 + (outp * 0x20)); 1013 ctrl = nv_rd32(priv, 0x660180 + (or * 0x20));
1007 if (ctrl & (1 << head)) 1014 if (ctrl & (1 << head))
1008 break; 1015 break;
1009 } 1016 }
1010 1017
1011 if (outp == 8) 1018 if (or == 8)
1012 return conf; 1019 return NULL;
1013 1020
1014 data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1); 1021 outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
1015 if (data == 0x0000) 1022 if (!outp)
1016 return conf; 1023 return NULL;
1017 1024
1018 switch (dcb->type) { 1025 switch (outp->info.type) {
1019 case DCB_OUTPUT_TMDS: 1026 case DCB_OUTPUT_TMDS:
1020 conf = (ctrl & 0x00000f00) >> 8; 1027 *conf = (ctrl & 0x00000f00) >> 8;
1021 if (pclk >= 165000) 1028 if (pclk >= 165000)
1022 conf |= 0x0100; 1029 *conf |= 0x0100;
1023 break; 1030 break;
1024 case DCB_OUTPUT_LVDS: 1031 case DCB_OUTPUT_LVDS:
1025 conf = priv->sor.lvdsconf; 1032 *conf = priv->sor.lvdsconf;
1026 break; 1033 break;
1027 case DCB_OUTPUT_DP: 1034 case DCB_OUTPUT_DP:
1028 conf = (ctrl & 0x00000f00) >> 8; 1035 *conf = (ctrl & 0x00000f00) >> 8;
1029 break; 1036 break;
1030 case DCB_OUTPUT_ANALOG: 1037 case DCB_OUTPUT_ANALOG:
1031 default: 1038 default:
1032 conf = 0x00ff; 1039 *conf = 0x00ff;
1033 break; 1040 break;
1034 } 1041 }
1035 1042
1036 data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); 1043 data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
1037 if (data && id < 0xff) { 1044 if (data && id < 0xff) {
1038 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); 1045 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
1039 if (data) { 1046 if (data) {
@@ -1041,7 +1048,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id,
1041 .subdev = nv_subdev(priv), 1048 .subdev = nv_subdev(priv),
1042 .bios = bios, 1049 .bios = bios,
1043 .offset = data, 1050 .offset = data,
1044 .outp = dcb, 1051 .outp = &outp->info,
1045 .crtc = head, 1052 .crtc = head,
1046 .execute = 1, 1053 .execute = 1,
1047 }; 1054 };
@@ -1050,7 +1057,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id,
1050 } 1057 }
1051 } 1058 }
1052 1059
1053 return conf; 1060 return outp;
1054} 1061}
1055 1062
1056static void 1063static void
@@ -1062,7 +1069,23 @@ nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head)
1062static void 1069static void
1063nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head) 1070nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head)
1064{ 1071{
1065 exec_script(priv, head, 2); 1072 struct nvkm_output *outp = exec_script(priv, head, 2);
1073
1074 /* see note in nv50_disp_intr_unk20_0() */
1075 if (outp && outp->info.type == DCB_OUTPUT_DP) {
1076 struct nvkm_output_dp *outpdp = (void *)outp;
1077 struct nvbios_init init = {
1078 .subdev = nv_subdev(priv),
1079 .bios = nouveau_bios(priv),
1080 .outp = &outp->info,
1081 .crtc = head,
1082 .offset = outpdp->info.script[4],
1083 .execute = 1,
1084 };
1085
1086 nvbios_exec(&init);
1087 atomic_set(&outpdp->lt.done, 0);
1088 }
1066} 1089}
1067 1090
1068static void 1091static void
@@ -1124,49 +1147,52 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
1124static void 1147static void
1125nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) 1148nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
1126{ 1149{
1127 struct dcb_output outp; 1150 struct nvkm_output *outp;
1128 u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; 1151 u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
1129 u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp); 1152 u32 conf, addr, data;
1130 if (conf != ~0) { 1153
1131 u32 addr, data; 1154 outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
1132 1155 if (!outp)
1133 if (outp.type == DCB_OUTPUT_DP) { 1156 return;
1134 u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300)); 1157
1135 switch ((sync & 0x000003c0) >> 6) { 1158 /* see note in nv50_disp_intr_unk20_2() */
1136 case 6: pclk = pclk * 30 / 8; break; 1159 if (outp->info.type == DCB_OUTPUT_DP) {
1137 case 5: pclk = pclk * 24 / 8; break; 1160 u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300));
1138 case 2: 1161 switch ((sync & 0x000003c0) >> 6) {
1139 default: 1162 case 6: pclk = pclk * 30 / 8; break;
1140 pclk = pclk * 18 / 8; 1163 case 5: pclk = pclk * 24 / 8; break;
1141 break; 1164 case 2:
1142 } 1165 default:
1143 1166 pclk = pclk * 18 / 8;
1144 nouveau_dp_train(&priv->base, priv->sor.dp, 1167 break;
1145 &outp, head, pclk);
1146 } 1168 }
1147 1169
1148 exec_clkcmp(priv, head, 0, pclk, &outp); 1170 if (nvkm_output_dp_train(outp, pclk, true))
1171 ERR("link not trained before attach\n");
1172 }
1149 1173
1150 if (outp.type == DCB_OUTPUT_ANALOG) { 1174 exec_clkcmp(priv, head, 0, pclk, &conf);
1151 addr = 0x612280 + (ffs(outp.or) - 1) * 0x800;
1152 data = 0x00000000;
1153 } else {
1154 if (outp.type == DCB_OUTPUT_DP)
1155 nvd0_disp_intr_unk2_2_tu(priv, head, &outp);
1156 addr = 0x612300 + (ffs(outp.or) - 1) * 0x800;
1157 data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
1158 }
1159 1175
1160 nv_mask(priv, addr, 0x00000707, data); 1176 if (outp->info.type == DCB_OUTPUT_ANALOG) {
1177 addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800;
1178 data = 0x00000000;
1179 } else {
1180 if (outp->info.type == DCB_OUTPUT_DP)
1181 nvd0_disp_intr_unk2_2_tu(priv, head, &outp->info);
1182 addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800;
1183 data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
1161 } 1184 }
1185
1186 nv_mask(priv, addr, 0x00000707, data);
1162} 1187}
1163 1188
1164static void 1189static void
1165nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head) 1190nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head)
1166{ 1191{
1167 struct dcb_output outp;
1168 u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; 1192 u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
1169 exec_clkcmp(priv, head, 1, pclk, &outp); 1193 u32 conf;
1194
1195 exec_clkcmp(priv, head, 1, pclk, &conf);
1170} 1196}
1171 1197
1172void 1198void
@@ -1240,7 +1266,7 @@ nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid)
1240 chid, (mthd & 0x0000ffc), data, mthd, unkn); 1266 chid, (mthd & 0x0000ffc), data, mthd, unkn);
1241 1267
1242 if (chid == 0) { 1268 if (chid == 0) {
1243 switch (mthd) { 1269 switch (mthd & 0xffc) {
1244 case 0x0080: 1270 case 0x0080:
1245 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0, 1271 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
1246 impl->mthd.core); 1272 impl->mthd.core);
@@ -1250,7 +1276,7 @@ nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid)
1250 } 1276 }
1251 } else 1277 } else
1252 if (chid <= 4) { 1278 if (chid <= 4) {
1253 switch (mthd) { 1279 switch (mthd & 0xffc) {
1254 case 0x0080: 1280 case 0x0080:
1255 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1, 1281 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
1256 impl->mthd.base); 1282 impl->mthd.base);
@@ -1260,7 +1286,7 @@ nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid)
1260 } 1286 }
1261 } else 1287 } else
1262 if (chid <= 8) { 1288 if (chid <= 8) {
1263 switch (mthd) { 1289 switch (mthd & 0xffc) {
1264 case 0x0080: 1290 case 0x0080:
1265 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5, 1291 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5,
1266 impl->mthd.ovly); 1292 impl->mthd.ovly);
@@ -1317,7 +1343,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
1317 if (mask & intr) { 1343 if (mask & intr) {
1318 u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); 1344 u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
1319 if (stat & 0x00000001) 1345 if (stat & 0x00000001)
1320 nouveau_event_trigger(priv->base.vblank, i); 1346 nouveau_event_trigger(priv->base.vblank, 1, i);
1321 nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); 1347 nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
1322 nv_rd32(priv, 0x6100c0 + (i * 0x800)); 1348 nv_rd32(priv, 0x6100c0 + (i * 0x800));
1323 } 1349 }
@@ -1352,11 +1378,16 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
1352 priv->sor.power = nv50_sor_power; 1378 priv->sor.power = nv50_sor_power;
1353 priv->sor.hda_eld = nvd0_hda_eld; 1379 priv->sor.hda_eld = nvd0_hda_eld;
1354 priv->sor.hdmi = nvd0_hdmi_ctrl; 1380 priv->sor.hdmi = nvd0_hdmi_ctrl;
1355 priv->sor.dp = &nvd0_sor_dp_func;
1356 return 0; 1381 return 0;
1357} 1382}
1358 1383
1359struct nouveau_oclass * 1384struct nouveau_oclass *
1385nvd0_disp_outp_sclass[] = {
1386 &nvd0_sor_dp_impl.base.base,
1387 NULL
1388};
1389
1390struct nouveau_oclass *
1360nvd0_disp_oclass = &(struct nv50_disp_impl) { 1391nvd0_disp_oclass = &(struct nv50_disp_impl) {
1361 .base.base.handle = NV_ENGINE(DISP, 0x90), 1392 .base.base.handle = NV_ENGINE(DISP, 0x90),
1362 .base.base.ofuncs = &(struct nouveau_ofuncs) { 1393 .base.base.ofuncs = &(struct nouveau_ofuncs) {
@@ -1365,6 +1396,7 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) {
1365 .init = _nouveau_disp_init, 1396 .init = _nouveau_disp_init,
1366 .fini = _nouveau_disp_fini, 1397 .fini = _nouveau_disp_fini,
1367 }, 1398 },
1399 .base.outp = nvd0_disp_outp_sclass,
1368 .mthd.core = &nvd0_disp_mast_mthd_chan, 1400 .mthd.core = &nvd0_disp_mast_mthd_chan,
1369 .mthd.base = &nvd0_disp_sync_mthd_chan, 1401 .mthd.base = &nvd0_disp_sync_mthd_chan,
1370 .mthd.ovly = &nvd0_disp_ovly_mthd_chan, 1402 .mthd.ovly = &nvd0_disp_ovly_mthd_chan,
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
index 44e0b8f34c1a..11328e3f5df1 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
@@ -246,7 +246,6 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
246 priv->sor.power = nv50_sor_power; 246 priv->sor.power = nv50_sor_power;
247 priv->sor.hda_eld = nvd0_hda_eld; 247 priv->sor.hda_eld = nvd0_hda_eld;
248 priv->sor.hdmi = nvd0_hdmi_ctrl; 248 priv->sor.hdmi = nvd0_hdmi_ctrl;
249 priv->sor.dp = &nvd0_sor_dp_func;
250 return 0; 249 return 0;
251} 250}
252 251
@@ -259,6 +258,7 @@ nve0_disp_oclass = &(struct nv50_disp_impl) {
259 .init = _nouveau_disp_init, 258 .init = _nouveau_disp_init,
260 .fini = _nouveau_disp_fini, 259 .fini = _nouveau_disp_fini,
261 }, 260 },
261 .base.outp = nvd0_disp_outp_sclass,
262 .mthd.core = &nve0_disp_mast_mthd_chan, 262 .mthd.core = &nve0_disp_mast_mthd_chan,
263 .mthd.base = &nvd0_disp_sync_mthd_chan, 263 .mthd.base = &nvd0_disp_sync_mthd_chan,
264 .mthd.ovly = &nve0_disp_ovly_mthd_chan, 264 .mthd.ovly = &nve0_disp_ovly_mthd_chan,
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
index 482585d375fa..104388081d73 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
@@ -81,7 +81,6 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
81 priv->sor.power = nv50_sor_power; 81 priv->sor.power = nv50_sor_power;
82 priv->sor.hda_eld = nvd0_hda_eld; 82 priv->sor.hda_eld = nvd0_hda_eld;
83 priv->sor.hdmi = nvd0_hdmi_ctrl; 83 priv->sor.hdmi = nvd0_hdmi_ctrl;
84 priv->sor.dp = &nvd0_sor_dp_func;
85 return 0; 84 return 0;
86} 85}
87 86
@@ -94,6 +93,7 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) {
94 .init = _nouveau_disp_init, 93 .init = _nouveau_disp_init,
95 .fini = _nouveau_disp_fini, 94 .fini = _nouveau_disp_fini,
96 }, 95 },
96 .base.outp = nvd0_disp_outp_sclass,
97 .mthd.core = &nve0_disp_mast_mthd_chan, 97 .mthd.core = &nve0_disp_mast_mthd_chan,
98 .mthd.base = &nvd0_disp_sync_mthd_chan, 98 .mthd.base = &nvd0_disp_sync_mthd_chan,
99 .mthd.ovly = &nve0_disp_ovly_mthd_chan, 99 .mthd.ovly = &nve0_disp_ovly_mthd_chan,
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outp.c
new file mode 100644
index 000000000000..ad9ba7ccec7f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/outp.c
@@ -0,0 +1,137 @@
1/*
2 * Copyright 2014 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/i2c.h>
26#include <subdev/bios.h>
27#include <subdev/bios/conn.h>
28
29#include "outp.h"
30
31int
32_nvkm_output_fini(struct nouveau_object *object, bool suspend)
33{
34 struct nvkm_output *outp = (void *)object;
35 nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend);
36 return nouveau_object_fini(&outp->base, suspend);
37}
38
39int
40_nvkm_output_init(struct nouveau_object *object)
41{
42 struct nvkm_output *outp = (void *)object;
43 int ret = nouveau_object_init(&outp->base);
44 if (ret == 0)
45 nv_ofuncs(outp->conn)->init(nv_object(outp->conn));
46 return 0;
47}
48
49void
50_nvkm_output_dtor(struct nouveau_object *object)
51{
52 struct nvkm_output *outp = (void *)object;
53 list_del(&outp->head);
54 nouveau_object_ref(NULL, (void *)&outp->conn);
55 nouveau_object_destroy(&outp->base);
56}
57
58int
59nvkm_output_create_(struct nouveau_object *parent,
60 struct nouveau_object *engine,
61 struct nouveau_oclass *oclass,
62 struct dcb_output *dcbE, int index,
63 int length, void **pobject)
64{
65 struct nouveau_bios *bios = nouveau_bios(engine);
66 struct nouveau_i2c *i2c = nouveau_i2c(parent);
67 struct nouveau_disp *disp = (void *)engine;
68 struct nvbios_connE connE;
69 struct nvkm_output *outp;
70 u8 ver, hdr;
71 u32 data;
72 int ret;
73
74 ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
75 outp = *pobject;
76 if (ret)
77 return ret;
78
79 outp->info = *dcbE;
80 outp->index = index;
81
82 DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n",
83 dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ?
84 dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index,
85 dcbE->bus, dcbE->heads);
86
87 outp->port = i2c->find(i2c, outp->info.i2c_index);
88 outp->edid = outp->port;
89
90 data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE);
91 if (!data) {
92 DBG("vbios connector data not found\n");
93 memset(&connE, 0x00, sizeof(connE));
94 connE.type = DCB_CONNECTOR_NONE;
95 }
96
97 ret = nouveau_object_ctor(parent, engine, nvkm_connector_oclass,
98 &connE, outp->info.connector,
99 (struct nouveau_object **)&outp->conn);
100 if (ret < 0) {
101 ERR("error %d creating connector, disabling\n", ret);
102 return ret;
103 }
104
105 list_add_tail(&outp->head, &disp->outp);
106 return 0;
107}
108
109int
110_nvkm_output_ctor(struct nouveau_object *parent,
111 struct nouveau_object *engine,
112 struct nouveau_oclass *oclass, void *dcbE, u32 index,
113 struct nouveau_object **pobject)
114{
115 struct nvkm_output *outp;
116 int ret;
117
118 ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp);
119 *pobject = nv_object(outp);
120 if (ret)
121 return ret;
122
123 return 0;
124}
125
126struct nouveau_oclass *
127nvkm_output_oclass = &(struct nvkm_output_impl) {
128 .base = {
129 .handle = 0,
130 .ofuncs = &(struct nouveau_ofuncs) {
131 .ctor = _nvkm_output_ctor,
132 .dtor = _nvkm_output_dtor,
133 .init = _nvkm_output_init,
134 .fini = _nvkm_output_fini,
135 },
136 },
137}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outp.h
new file mode 100644
index 000000000000..bc76fbf85710
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/outp.h
@@ -0,0 +1,59 @@
1#ifndef __NVKM_DISP_OUTP_H__
2#define __NVKM_DISP_OUTP_H__
3
4#include "priv.h"
5
6struct nvkm_output {
7 struct nouveau_object base;
8 struct list_head head;
9
10 struct dcb_output info;
11 int index;
12
13 struct nouveau_i2c_port *port;
14 struct nouveau_i2c_port *edid;
15
16 struct nvkm_connector *conn;
17};
18
19#define nvkm_output_create(p,e,c,b,i,d) \
20 nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
21#define nvkm_output_destroy(d) ({ \
22 struct nvkm_output *_outp = (d); \
23 _nvkm_output_dtor(nv_object(_outp)); \
24})
25#define nvkm_output_init(d) ({ \
26 struct nvkm_output *_outp = (d); \
27 _nvkm_output_init(nv_object(_outp)); \
28})
29#define nvkm_output_fini(d,s) ({ \
30 struct nvkm_output *_outp = (d); \
31 _nvkm_output_fini(nv_object(_outp), (s)); \
32})
33
34int nvkm_output_create_(struct nouveau_object *, struct nouveau_object *,
35 struct nouveau_oclass *, struct dcb_output *,
36 int, int, void **);
37
38int _nvkm_output_ctor(struct nouveau_object *, struct nouveau_object *,
39 struct nouveau_oclass *, void *, u32,
40 struct nouveau_object **);
41void _nvkm_output_dtor(struct nouveau_object *);
42int _nvkm_output_init(struct nouveau_object *);
43int _nvkm_output_fini(struct nouveau_object *, bool);
44
45struct nvkm_output_impl {
46 struct nouveau_oclass base;
47};
48
49#ifndef MSG
50#define MSG(l,f,a...) do { \
51 struct nvkm_output *_outp = (void *)outp; \
52 nv_##l(nv_object(outp)->engine, "%02x:%04x:%04x: "f, _outp->index, \
53 _outp->info.hasht, _outp->info.hashm, ##a); \
54} while(0)
55#define DBG(f,a...) MSG(debug, f, ##a)
56#define ERR(f,a...) MSG(error, f, ##a)
57#endif
58
59#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
new file mode 100644
index 000000000000..52c299c3d300
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
@@ -0,0 +1,276 @@
1/*
2 * Copyright 2014 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/i2c.h>
26
27#include "outpdp.h"
28#include "conn.h"
29#include "dport.h"
30
31int
32nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
33{
34 struct nvkm_output_dp *outp = (void *)base;
35 bool retrain = true;
36 u8 link[2], stat[3];
37 u32 rate;
38 int ret, i;
39
40 /* check that the link is trained at a high enough rate */
41 ret = nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, link, 2);
42 if (ret) {
43 DBG("failed to read link config, assuming no sink\n");
44 goto done;
45 }
46
47 rate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET);
48 if (rate < ((datarate / 8) * 10)) {
49 DBG("link not trained at sufficient rate\n");
50 goto done;
51 }
52
53 /* check that link is still trained */
54 ret = nv_rdaux(outp->base.edid, DPCD_LS02, stat, 3);
55 if (ret) {
56 DBG("failed to read link status, assuming no sink\n");
57 goto done;
58 }
59
60 if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) {
61 for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) {
62 u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f;
63 if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
64 !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
65 !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
66 DBG("lane %d not equalised\n", lane);
67 goto done;
68 }
69 }
70 retrain = false;
71 } else {
72 DBG("no inter-lane alignment\n");
73 }
74
75done:
76 if (retrain || !atomic_read(&outp->lt.done)) {
77 /* no sink, but still need to configure source */
78 if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) {
79 outp->dpcd[DPCD_RC01_MAX_LINK_RATE] =
80 outp->base.info.dpconf.link_bw;
81 outp->dpcd[DPCD_RC02] =
82 outp->base.info.dpconf.link_nr;
83 }
84 atomic_set(&outp->lt.done, 0);
85 schedule_work(&outp->lt.work);
86 } else {
87 nouveau_event_get(outp->irq);
88 }
89
90 if (wait) {
91 if (!wait_event_timeout(outp->lt.wait,
92 atomic_read(&outp->lt.done),
93 msecs_to_jiffies(2000)))
94 ret = -ETIMEDOUT;
95 }
96
97 return ret;
98}
99
100static void
101nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present)
102{
103 struct nouveau_i2c_port *port = outp->base.edid;
104 if (present) {
105 if (!outp->present) {
106 nouveau_i2c(port)->acquire_pad(port, 0);
107 DBG("aux power -> always\n");
108 outp->present = true;
109 }
110 nvkm_output_dp_train(&outp->base, 0, true);
111 } else {
112 if (outp->present) {
113 nouveau_i2c(port)->release_pad(port);
114 DBG("aux power -> demand\n");
115 outp->present = false;
116 }
117 atomic_set(&outp->lt.done, 0);
118 }
119}
120
121static void
122nvkm_output_dp_detect(struct nvkm_output_dp *outp)
123{
124 struct nouveau_i2c_port *port = outp->base.edid;
125 int ret = nouveau_i2c(port)->acquire_pad(port, 0);
126 if (ret == 0) {
127 ret = nv_rdaux(outp->base.edid, DPCD_RC00_DPCD_REV,
128 outp->dpcd, sizeof(outp->dpcd));
129 nvkm_output_dp_enable(outp, ret == 0);
130 nouveau_i2c(port)->release_pad(port);
131 }
132}
133
134static void
135nvkm_output_dp_service_work(struct work_struct *work)
136{
137 struct nvkm_output_dp *outp = container_of(work, typeof(*outp), work);
138 struct nouveau_disp *disp = nouveau_disp(outp);
139 int type = atomic_xchg(&outp->pending, 0);
140 u32 send = 0;
141
142 if (type & (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG)) {
143 nvkm_output_dp_detect(outp);
144 if (type & NVKM_I2C_UNPLUG)
145 send |= NVKM_HPD_UNPLUG;
146 if (type & NVKM_I2C_PLUG)
147 send |= NVKM_HPD_PLUG;
148 nouveau_event_get(outp->base.conn->hpd.event);
149 }
150
151 if (type & NVKM_I2C_IRQ) {
152 nvkm_output_dp_train(&outp->base, 0, true);
153 send |= NVKM_HPD_IRQ;
154 }
155
156 nouveau_event_trigger(disp->hpd, send, outp->base.info.connector);
157}
158
159static int
160nvkm_output_dp_service(void *data, u32 type, int index)
161{
162 struct nvkm_output_dp *outp = data;
163 DBG("HPD: %d\n", type);
164 atomic_or(type, &outp->pending);
165 schedule_work(&outp->work);
166 return NVKM_EVENT_DROP;
167}
168
169int
170_nvkm_output_dp_fini(struct nouveau_object *object, bool suspend)
171{
172 struct nvkm_output_dp *outp = (void *)object;
173 nouveau_event_put(outp->irq);
174 nvkm_output_dp_enable(outp, false);
175 return nvkm_output_fini(&outp->base, suspend);
176}
177
178int
179_nvkm_output_dp_init(struct nouveau_object *object)
180{
181 struct nvkm_output_dp *outp = (void *)object;
182 nvkm_output_dp_detect(outp);
183 return nvkm_output_init(&outp->base);
184}
185
186void
187_nvkm_output_dp_dtor(struct nouveau_object *object)
188{
189 struct nvkm_output_dp *outp = (void *)object;
190 nouveau_event_ref(NULL, &outp->irq);
191 nvkm_output_destroy(&outp->base);
192}
193
194int
195nvkm_output_dp_create_(struct nouveau_object *parent,
196 struct nouveau_object *engine,
197 struct nouveau_oclass *oclass,
198 struct dcb_output *info, int index,
199 int length, void **pobject)
200{
201 struct nouveau_bios *bios = nouveau_bios(parent);
202 struct nouveau_i2c *i2c = nouveau_i2c(parent);
203 struct nvkm_output_dp *outp;
204 u8 hdr, cnt, len;
205 u32 data;
206 int ret;
207
208 ret = nvkm_output_create_(parent, engine, oclass, info, index,
209 length, pobject);
210 outp = *pobject;
211 if (ret)
212 return ret;
213
214 nouveau_event_ref(NULL, &outp->base.conn->hpd.event);
215
216 /* access to the aux channel is not optional... */
217 if (!outp->base.edid) {
218 ERR("aux channel not found\n");
219 return -ENODEV;
220 }
221
222 /* nor is the bios data for this output... */
223 data = nvbios_dpout_match(bios, outp->base.info.hasht,
224 outp->base.info.hashm, &outp->version,
225 &hdr, &cnt, &len, &outp->info);
226 if (!data) {
227 ERR("no bios dp data\n");
228 return -ENODEV;
229 }
230
231 DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len);
232
233 /* link training */
234 INIT_WORK(&outp->lt.work, nouveau_dp_train);
235 init_waitqueue_head(&outp->lt.wait);
236 atomic_set(&outp->lt.done, 0);
237
238 /* link maintenance */
239 ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_IRQ, outp->base.edid->index,
240 nvkm_output_dp_service, outp, &outp->irq);
241 if (ret) {
242 ERR("error monitoring aux irq event: %d\n", ret);
243 return ret;
244 }
245
246 INIT_WORK(&outp->work, nvkm_output_dp_service_work);
247
248 /* hotplug detect, replaces gpio-based mechanism with aux events */
249 ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
250 outp->base.edid->index,
251 nvkm_output_dp_service, outp,
252 &outp->base.conn->hpd.event);
253 if (ret) {
254 ERR("error monitoring aux hpd events: %d\n", ret);
255 return ret;
256 }
257
258 return 0;
259}
260
261int
262_nvkm_output_dp_ctor(struct nouveau_object *parent,
263 struct nouveau_object *engine,
264 struct nouveau_oclass *oclass, void *info, u32 index,
265 struct nouveau_object **pobject)
266{
267 struct nvkm_output_dp *outp;
268 int ret;
269
270 ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
271 *pobject = nv_object(outp);
272 if (ret)
273 return ret;
274
275 return 0;
276}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h
new file mode 100644
index 000000000000..ff33ba12cb67
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h
@@ -0,0 +1,65 @@
1#ifndef __NVKM_DISP_OUTP_DP_H__
2#define __NVKM_DISP_OUTP_DP_H__
3
4#include <subdev/bios.h>
5#include <subdev/bios/dp.h>
6
7#include "outp.h"
8
9struct nvkm_output_dp {
10 struct nvkm_output base;
11
12 struct nvbios_dpout info;
13 u8 version;
14
15 struct nouveau_eventh *irq;
16 struct nouveau_eventh *hpd;
17 struct work_struct work;
18 atomic_t pending;
19 bool present;
20 u8 dpcd[16];
21
22 struct {
23 struct work_struct work;
24 wait_queue_head_t wait;
25 atomic_t done;
26 } lt;
27};
28
29#define nvkm_output_dp_create(p,e,c,b,i,d) \
30 nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
31#define nvkm_output_dp_destroy(d) ({ \
32 struct nvkm_output_dp *_outp = (d); \
33 _nvkm_output_dp_dtor(nv_object(_outp)); \
34})
35#define nvkm_output_dp_init(d) ({ \
36 struct nvkm_output_dp *_outp = (d); \
37 _nvkm_output_dp_init(nv_object(_outp)); \
38})
39#define nvkm_output_dp_fini(d,s) ({ \
40 struct nvkm_output_dp *_outp = (d); \
41 _nvkm_output_dp_fini(nv_object(_outp), (s)); \
42})
43
44int nvkm_output_dp_create_(struct nouveau_object *, struct nouveau_object *,
45 struct nouveau_oclass *, struct dcb_output *,
46 int, int, void **);
47
48int _nvkm_output_dp_ctor(struct nouveau_object *, struct nouveau_object *,
49 struct nouveau_oclass *, void *, u32,
50 struct nouveau_object **);
51void _nvkm_output_dp_dtor(struct nouveau_object *);
52int _nvkm_output_dp_init(struct nouveau_object *);
53int _nvkm_output_dp_fini(struct nouveau_object *, bool);
54
55struct nvkm_output_dp_impl {
56 struct nvkm_output_impl base;
57 int (*pattern)(struct nvkm_output_dp *, int);
58 int (*lnk_pwr)(struct nvkm_output_dp *, int nr);
59 int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef);
60 int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc);
61};
62
63int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait);
64
65#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
index 2c8ce351b52d..fe0f256f11bf 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
@@ -33,68 +33,107 @@
33#include "nv50.h" 33#include "nv50.h"
34 34
35/****************************************************************************** 35/******************************************************************************
36 * DisplayPort 36 * TMDS
37 *****************************************************************************/ 37 *****************************************************************************/
38static struct nouveau_i2c_port * 38
39nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp) 39static int
40nv50_pior_tmds_ctor(struct nouveau_object *parent,
41 struct nouveau_object *engine,
42 struct nouveau_oclass *oclass, void *info, u32 index,
43 struct nouveau_object **pobject)
40{ 44{
41 struct nouveau_i2c *i2c = nouveau_i2c(disp); 45 struct nouveau_i2c *i2c = nouveau_i2c(parent);
42 return i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev)); 46 struct nvkm_output *outp;
47 int ret;
48
49 ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
50 *pobject = nv_object(outp);
51 if (ret)
52 return ret;
53
54 outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev));
55 return 0;
43} 56}
44 57
58struct nvkm_output_impl
59nv50_pior_tmds_impl = {
60 .base.handle = DCB_OUTPUT_TMDS | 0x0100,
61 .base.ofuncs = &(struct nouveau_ofuncs) {
62 .ctor = nv50_pior_tmds_ctor,
63 .dtor = _nvkm_output_dtor,
64 .init = _nvkm_output_init,
65 .fini = _nvkm_output_fini,
66 },
67};
68
69/******************************************************************************
70 * DisplayPort
71 *****************************************************************************/
72
45static int 73static int
46nv50_pior_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, 74nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern)
47 int head, int pattern)
48{ 75{
49 struct nouveau_i2c_port *port; 76 struct nouveau_i2c_port *port = outp->base.edid;
50 int ret = -EINVAL; 77 if (port && port->func->pattern)
51 78 return port->func->pattern(port, pattern);
52 port = nv50_pior_dp_find(disp, outp); 79 return port ? 0 : -ENODEV;
53 if (port) {
54 if (port->func->pattern)
55 ret = port->func->pattern(port, pattern);
56 else
57 ret = 0;
58 }
59
60 return ret;
61} 80}
62 81
63static int 82static int
64nv50_pior_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, 83nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
65 int head, int lane_nr, int link_bw, bool enh)
66{ 84{
67 struct nouveau_i2c_port *port; 85 return 0;
68 int ret = -EINVAL; 86}
69 87
70 port = nv50_pior_dp_find(disp, outp); 88static int
89nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
90{
91 struct nouveau_i2c_port *port = outp->base.edid;
71 if (port && port->func->lnk_ctl) 92 if (port && port->func->lnk_ctl)
72 ret = port->func->lnk_ctl(port, lane_nr, link_bw, enh); 93 return port->func->lnk_ctl(port, nr, bw, ef);
94 return port ? 0 : -ENODEV;
95}
73 96
74 return ret; 97static int
98nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
99{
100 struct nouveau_i2c_port *port = outp->base.edid;
101 if (port && port->func->drv_ctl)
102 return port->func->drv_ctl(port, ln, vs, pe);
103 return port ? 0 : -ENODEV;
75} 104}
76 105
77static int 106static int
78nv50_pior_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, 107nv50_pior_dp_ctor(struct nouveau_object *parent,
79 int head, int lane, int vsw, int pre) 108 struct nouveau_object *engine,
109 struct nouveau_oclass *oclass, void *info, u32 index,
110 struct nouveau_object **pobject)
80{ 111{
81 struct nouveau_i2c_port *port; 112 struct nouveau_i2c *i2c = nouveau_i2c(parent);
82 int ret = -EINVAL; 113 struct nvkm_output_dp *outp;
83 114 int ret;
84 port = nv50_pior_dp_find(disp, outp);
85 if (port) {
86 if (port->func->drv_ctl)
87 ret = port->func->drv_ctl(port, lane, vsw, pre);
88 else
89 ret = 0;
90 }
91 115
92 return ret; 116 ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
117 *pobject = nv_object(outp);
118 if (ret)
119 return ret;
120
121 outp->base.edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(
122 outp->base.info.extdev));
123 return 0;
93} 124}
94 125
95const struct nouveau_dp_func 126struct nvkm_output_dp_impl
96nv50_pior_dp_func = { 127nv50_pior_dp_impl = {
128 .base.base.handle = DCB_OUTPUT_DP | 0x0010,
129 .base.base.ofuncs = &(struct nouveau_ofuncs) {
130 .ctor = nv50_pior_dp_ctor,
131 .dtor = _nvkm_output_dp_dtor,
132 .init = _nvkm_output_dp_init,
133 .fini = _nvkm_output_dp_fini,
134 },
97 .pattern = nv50_pior_dp_pattern, 135 .pattern = nv50_pior_dp_pattern,
136 .lnk_pwr = nv50_pior_dp_lnk_pwr,
98 .lnk_ctl = nv50_pior_dp_lnk_ctl, 137 .lnk_ctl = nv50_pior_dp_lnk_ctl,
99 .drv_ctl = nv50_pior_dp_drv_ctl, 138 .drv_ctl = nv50_pior_dp_drv_ctl,
100}; 139};
@@ -102,6 +141,7 @@ nv50_pior_dp_func = {
102/****************************************************************************** 141/******************************************************************************
103 * General PIOR handling 142 * General PIOR handling
104 *****************************************************************************/ 143 *****************************************************************************/
144
105int 145int
106nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data) 146nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data)
107{ 147{
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
index cc3c7a4ca747..26e9a42569c7 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
@@ -1,10 +1,42 @@
1#ifndef __NVKM_DISP_PRIV_H__ 1#ifndef __NVKM_DISP_PRIV_H__
2#define __NVKM_DISP_PRIV_H__ 2#define __NVKM_DISP_PRIV_H__
3 3
4#include <subdev/bios.h>
5#include <subdev/bios/dcb.h>
6#include <subdev/bios/conn.h>
7
4#include <engine/disp.h> 8#include <engine/disp.h>
5 9
6struct nouveau_disp_impl { 10struct nouveau_disp_impl {
7 struct nouveau_oclass base; 11 struct nouveau_oclass base;
12 struct nouveau_oclass **outp;
13 struct nouveau_oclass **conn;
8}; 14};
9 15
16#define nouveau_disp_create(p,e,c,h,i,x,d) \
17 nouveau_disp_create_((p), (e), (c), (h), (i), (x), \
18 sizeof(**d), (void **)d)
19#define nouveau_disp_destroy(d) ({ \
20 struct nouveau_disp *disp = (d); \
21 _nouveau_disp_dtor(nv_object(disp)); \
22})
23#define nouveau_disp_init(d) ({ \
24 struct nouveau_disp *disp = (d); \
25 _nouveau_disp_init(nv_object(disp)); \
26})
27#define nouveau_disp_fini(d,s) ({ \
28 struct nouveau_disp *disp = (d); \
29 _nouveau_disp_fini(nv_object(disp), (s)); \
30})
31
32int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *,
33 struct nouveau_oclass *, int heads,
34 const char *, const char *, int, void **);
35void _nouveau_disp_dtor(struct nouveau_object *);
36int _nouveau_disp_init(struct nouveau_object *);
37int _nouveau_disp_fini(struct nouveau_object *, bool);
38
39extern struct nouveau_oclass *nvkm_output_oclass;
40extern struct nouveau_oclass *nvkm_connector_oclass;
41
10#endif 42#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
index 526b75242899..e1832778e8b6 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
@@ -47,8 +47,12 @@ int
47nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) 47nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
48{ 48{
49 struct nv50_disp_priv *priv = (void *)object->engine; 49 struct nv50_disp_priv *priv = (void *)object->engine;
50 const u8 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
50 const u8 head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3; 51 const u8 head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
52 const u8 link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
51 const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR); 53 const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR);
54 const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
55 struct nvkm_output *outp = NULL, *temp;
52 u32 data; 56 u32 data;
53 int ret = -EINVAL; 57 int ret = -EINVAL;
54 58
@@ -56,6 +60,13 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
56 return -EINVAL; 60 return -EINVAL;
57 data = *(u32 *)args; 61 data = *(u32 *)args;
58 62
63 list_for_each_entry(temp, &priv->base.outp, head) {
64 if ((temp->info.hasht & 0xff) == type &&
65 (temp->info.hashm & mask) == mask) {
66 outp = temp;
67 break;
68 }
69 }
59 70
60 switch (mthd & ~0x3f) { 71 switch (mthd & ~0x3f) {
61 case NV50_DISP_SOR_PWR: 72 case NV50_DISP_SOR_PWR:
@@ -71,6 +82,23 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
71 priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID; 82 priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID;
72 ret = 0; 83 ret = 0;
73 break; 84 break;
85 case NV94_DISP_SOR_DP_PWR:
86 if (outp) {
87 struct nvkm_output_dp *outpdp = (void *)outp;
88 switch (data) {
89 case NV94_DISP_SOR_DP_PWR_STATE_OFF:
90 ((struct nvkm_output_dp_impl *)nv_oclass(outp))
91 ->lnk_pwr(outpdp, 0);
92 atomic_set(&outpdp->lt.done, 0);
93 break;
94 case NV94_DISP_SOR_DP_PWR_STATE_ON:
95 nvkm_output_dp_train(&outpdp->base, 0, true);
96 break;
97 default:
98 return -EINVAL;
99 }
100 }
101 break;
74 default: 102 default:
75 BUG_ON(1); 103 BUG_ON(1);
76 } 104 }
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c
index eea3ef59693d..05487cda84a8 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c
@@ -29,19 +29,21 @@
29#include <subdev/bios/dcb.h> 29#include <subdev/bios/dcb.h>
30#include <subdev/bios/dp.h> 30#include <subdev/bios/dp.h>
31#include <subdev/bios/init.h> 31#include <subdev/bios/init.h>
32#include <subdev/timer.h>
32 33
33#include "nv50.h" 34#include "nv50.h"
35#include "outpdp.h"
34 36
35static inline u32 37static inline u32
36nv94_sor_soff(struct dcb_output *outp) 38nv94_sor_soff(struct nvkm_output_dp *outp)
37{ 39{
38 return (ffs(outp->or) - 1) * 0x800; 40 return (ffs(outp->base.info.or) - 1) * 0x800;
39} 41}
40 42
41static inline u32 43static inline u32
42nv94_sor_loff(struct dcb_output *outp) 44nv94_sor_loff(struct nvkm_output_dp *outp)
43{ 45{
44 return nv94_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80; 46 return nv94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
45} 47}
46 48
47static inline u32 49static inline u32
@@ -55,77 +57,96 @@ nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
55} 57}
56 58
57static int 59static int
58nv94_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, 60nv94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
59 int head, int pattern)
60{ 61{
61 struct nv50_disp_priv *priv = (void *)disp; 62 struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
62 const u32 loff = nv94_sor_loff(outp); 63 const u32 loff = nv94_sor_loff(outp);
63 nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24); 64 nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24);
64 return 0; 65 return 0;
65} 66}
66 67
68int
69nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
70{
71 struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
72 const u32 soff = nv94_sor_soff(outp);
73 const u32 loff = nv94_sor_loff(outp);
74 u32 mask = 0, i;
75
76 for (i = 0; i < nr; i++)
77 mask |= 1 << (nv94_sor_dp_lane_map(priv, i) >> 3);
78
79 nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
80 nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
81 nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
82 return 0;
83}
84
67static int 85static int
68nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, 86nv94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
69 int head, int link_nr, int link_bw, bool enh_frame)
70{ 87{
71 struct nv50_disp_priv *priv = (void *)disp; 88 struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
72 const u32 soff = nv94_sor_soff(outp); 89 const u32 soff = nv94_sor_soff(outp);
73 const u32 loff = nv94_sor_loff(outp); 90 const u32 loff = nv94_sor_loff(outp);
74 u32 dpctrl = 0x00000000; 91 u32 dpctrl = 0x00000000;
75 u32 clksor = 0x00000000; 92 u32 clksor = 0x00000000;
76 u32 lane = 0;
77 int i;
78 93
79 dpctrl |= ((1 << link_nr) - 1) << 16; 94 dpctrl |= ((1 << nr) - 1) << 16;
80 if (enh_frame) 95 if (ef)
81 dpctrl |= 0x00004000; 96 dpctrl |= 0x00004000;
82 if (link_bw > 0x06) 97 if (bw > 0x06)
83 clksor |= 0x00040000; 98 clksor |= 0x00040000;
84 99
85 for (i = 0; i < link_nr; i++)
86 lane |= 1 << (nv94_sor_dp_lane_map(priv, i) >> 3);
87
88 nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor); 100 nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor);
89 nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl); 101 nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
90 nv_mask(priv, 0x61c130 + loff, 0x0000000f, lane);
91 return 0; 102 return 0;
92} 103}
93 104
94static int 105static int
95nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, 106nv94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
96 int head, int lane, int swing, int preem)
97{ 107{
98 struct nouveau_bios *bios = nouveau_bios(disp); 108 struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
99 struct nv50_disp_priv *priv = (void *)disp; 109 struct nouveau_bios *bios = nouveau_bios(priv);
100 const u32 shift = nv94_sor_dp_lane_map(priv, lane); 110 const u32 shift = nv94_sor_dp_lane_map(priv, ln);
101 const u32 loff = nv94_sor_loff(outp); 111 const u32 loff = nv94_sor_loff(outp);
102 u32 addr, data[3]; 112 u32 addr, data[3];
103 u8 ver, hdr, cnt, len; 113 u8 ver, hdr, cnt, len;
104 struct nvbios_dpout info; 114 struct nvbios_dpout info;
105 struct nvbios_dpcfg ocfg; 115 struct nvbios_dpcfg ocfg;
106 116
107 addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm, 117 addr = nvbios_dpout_match(bios, outp->base.info.hasht,
118 outp->base.info.hashm,
108 &ver, &hdr, &cnt, &len, &info); 119 &ver, &hdr, &cnt, &len, &info);
109 if (!addr) 120 if (!addr)
110 return -ENODEV; 121 return -ENODEV;
111 122
112 addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, 123 addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe,
113 &ver, &hdr, &cnt, &len, &ocfg); 124 &ver, &hdr, &cnt, &len, &ocfg);
114 if (!addr) 125 if (!addr)
115 return -EINVAL; 126 return -EINVAL;
116 127
117 data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); 128 data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
118 data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); 129 data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
119 data[2] = nv_rd32(priv, 0x61c130 + loff) & ~(0x0000ff00); 130 data[2] = nv_rd32(priv, 0x61c130 + loff);
120 nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.drv << shift)); 131 if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
121 nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pre << shift)); 132 data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
122 nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.unk << 8)); 133 nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
134 nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
135 nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
123 return 0; 136 return 0;
124} 137}
125 138
126const struct nouveau_dp_func 139struct nvkm_output_dp_impl
127nv94_sor_dp_func = { 140nv94_sor_dp_impl = {
141 .base.base.handle = DCB_OUTPUT_DP,
142 .base.base.ofuncs = &(struct nouveau_ofuncs) {
143 .ctor = _nvkm_output_dp_ctor,
144 .dtor = _nvkm_output_dp_dtor,
145 .init = _nvkm_output_dp_init,
146 .fini = _nvkm_output_dp_fini,
147 },
128 .pattern = nv94_sor_dp_pattern, 148 .pattern = nv94_sor_dp_pattern,
149 .lnk_pwr = nv94_sor_dp_lnk_pwr,
129 .lnk_ctl = nv94_sor_dp_lnk_ctl, 150 .lnk_ctl = nv94_sor_dp_lnk_ctl,
130 .drv_ctl = nv94_sor_dp_drv_ctl, 151 .drv_ctl = nv94_sor_dp_drv_ctl,
131}; 152};
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
index d2df572f16a3..97f0e9cd3d40 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
@@ -29,19 +29,20 @@
29#include <subdev/bios/dcb.h> 29#include <subdev/bios/dcb.h>
30#include <subdev/bios/dp.h> 30#include <subdev/bios/dp.h>
31#include <subdev/bios/init.h> 31#include <subdev/bios/init.h>
32#include <subdev/timer.h>
32 33
33#include "nv50.h" 34#include "nv50.h"
34 35
35static inline u32 36static inline u32
36nvd0_sor_soff(struct dcb_output *outp) 37nvd0_sor_soff(struct nvkm_output_dp *outp)
37{ 38{
38 return (ffs(outp->or) - 1) * 0x800; 39 return (ffs(outp->base.info.or) - 1) * 0x800;
39} 40}
40 41
41static inline u32 42static inline u32
42nvd0_sor_loff(struct dcb_output *outp) 43nvd0_sor_loff(struct nvkm_output_dp *outp)
43{ 44{
44 return nvd0_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80; 45 return nvd0_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
45} 46}
46 47
47static inline u32 48static inline u32
@@ -52,77 +53,80 @@ nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
52} 53}
53 54
54static int 55static int
55nvd0_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, 56nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
56 int head, int pattern)
57{ 57{
58 struct nv50_disp_priv *priv = (void *)disp; 58 struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
59 const u32 loff = nvd0_sor_loff(outp); 59 const u32 loff = nvd0_sor_loff(outp);
60 nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); 60 nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
61 return 0; 61 return 0;
62} 62}
63 63
64static int 64static int
65nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, 65nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
66 int head, int link_nr, int link_bw, bool enh_frame)
67{ 66{
68 struct nv50_disp_priv *priv = (void *)disp; 67 struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
69 const u32 soff = nvd0_sor_soff(outp); 68 const u32 soff = nvd0_sor_soff(outp);
70 const u32 loff = nvd0_sor_loff(outp); 69 const u32 loff = nvd0_sor_loff(outp);
71 u32 dpctrl = 0x00000000; 70 u32 dpctrl = 0x00000000;
72 u32 clksor = 0x00000000; 71 u32 clksor = 0x00000000;
73 u32 lane = 0;
74 int i;
75 72
76 clksor |= link_bw << 18; 73 clksor |= bw << 18;
77 dpctrl |= ((1 << link_nr) - 1) << 16; 74 dpctrl |= ((1 << nr) - 1) << 16;
78 if (enh_frame) 75 if (ef)
79 dpctrl |= 0x00004000; 76 dpctrl |= 0x00004000;
80 77
81 for (i = 0; i < link_nr; i++)
82 lane |= 1 << (nvd0_sor_dp_lane_map(priv, i) >> 3);
83
84 nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor); 78 nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor);
85 nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl); 79 nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
86 nv_mask(priv, 0x61c130 + loff, 0x0000000f, lane);
87 return 0; 80 return 0;
88} 81}
89 82
90static int 83static int
91nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, 84nvd0_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
92 int head, int lane, int swing, int preem)
93{ 85{
94 struct nouveau_bios *bios = nouveau_bios(disp); 86 struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
95 struct nv50_disp_priv *priv = (void *)disp; 87 struct nouveau_bios *bios = nouveau_bios(priv);
96 const u32 shift = nvd0_sor_dp_lane_map(priv, lane); 88 const u32 shift = nvd0_sor_dp_lane_map(priv, ln);
97 const u32 loff = nvd0_sor_loff(outp); 89 const u32 loff = nvd0_sor_loff(outp);
98 u32 addr, data[3]; 90 u32 addr, data[4];
99 u8 ver, hdr, cnt, len; 91 u8 ver, hdr, cnt, len;
100 struct nvbios_dpout info; 92 struct nvbios_dpout info;
101 struct nvbios_dpcfg ocfg; 93 struct nvbios_dpcfg ocfg;
102 94
103 addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm, 95 addr = nvbios_dpout_match(bios, outp->base.info.hasht,
96 outp->base.info.hashm,
104 &ver, &hdr, &cnt, &len, &info); 97 &ver, &hdr, &cnt, &len, &info);
105 if (!addr) 98 if (!addr)
106 return -ENODEV; 99 return -ENODEV;
107 100
108 addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, 101 addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
109 &ver, &hdr, &cnt, &len, &ocfg); 102 &ver, &hdr, &cnt, &len, &ocfg);
110 if (!addr) 103 if (!addr)
111 return -EINVAL; 104 return -EINVAL;
112 105
113 data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); 106 data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
114 data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); 107 data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
115 data[2] = nv_rd32(priv, 0x61c130 + loff) & ~(0x0000ff00); 108 data[2] = nv_rd32(priv, 0x61c130 + loff);
116 nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.drv << shift)); 109 if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
117 nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pre << shift)); 110 data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
118 nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.unk << 8)); 111 nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
119 nv_mask(priv, 0x61c13c + loff, 0x00000000, 0x00000000); 112 nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
113 nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
114 data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
115 nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
120 return 0; 116 return 0;
121} 117}
122 118
123const struct nouveau_dp_func 119struct nvkm_output_dp_impl
124nvd0_sor_dp_func = { 120nvd0_sor_dp_impl = {
121 .base.base.handle = DCB_OUTPUT_DP,
122 .base.base.ofuncs = &(struct nouveau_ofuncs) {
123 .ctor = _nvkm_output_dp_ctor,
124 .dtor = _nvkm_output_dp_dtor,
125 .init = _nvkm_output_dp_init,
126 .fini = _nvkm_output_dp_fini,
127 },
125 .pattern = nvd0_sor_dp_pattern, 128 .pattern = nvd0_sor_dp_pattern,
129 .lnk_pwr = nv94_sor_dp_lnk_pwr,
126 .lnk_ctl = nvd0_sor_dp_lnk_ctl, 130 .lnk_ctl = nvd0_sor_dp_lnk_ctl,
127 .drv_ctl = nvd0_sor_dp_drv_ctl, 131 .drv_ctl = nvd0_sor_dp_drv_ctl,
128}; 132};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
index 6f9041ced9a2..56ed3d73bf8e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
@@ -91,7 +91,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
91 if (!chan->user) 91 if (!chan->user)
92 return -EFAULT; 92 return -EFAULT;
93 93
94 nouveau_event_trigger(priv->cevent, 0); 94 nouveau_event_trigger(priv->cevent, 1, 0);
95 95
96 chan->size = size; 96 chan->size = size;
97 return 0; 97 return 0;
@@ -194,11 +194,11 @@ nouveau_fifo_create_(struct nouveau_object *parent,
194 if (!priv->channel) 194 if (!priv->channel)
195 return -ENOMEM; 195 return -ENOMEM;
196 196
197 ret = nouveau_event_create(1, &priv->cevent); 197 ret = nouveau_event_create(1, 1, &priv->cevent);
198 if (ret) 198 if (ret)
199 return ret; 199 return ret;
200 200
201 ret = nouveau_event_create(1, &priv->uevent); 201 ret = nouveau_event_create(1, 1, &priv->uevent);
202 if (ret) 202 if (ret)
203 return ret; 203 return ret;
204 204
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
index 54f26cc801c7..c61b16a63884 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
@@ -539,7 +539,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
539 } 539 }
540 540
541 if (status & 0x40000000) { 541 if (status & 0x40000000) {
542 nouveau_event_trigger(priv->base.uevent, 0); 542 nouveau_event_trigger(priv->base.uevent, 1, 0);
543 nv_wr32(priv, 0x002100, 0x40000000); 543 nv_wr32(priv, 0x002100, 0x40000000);
544 status &= ~0x40000000; 544 status &= ~0x40000000;
545 } 545 }
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
index fe0f41e65d9b..6e5ac16e5460 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
@@ -389,14 +389,14 @@ nv84_fifo_cclass = {
389 ******************************************************************************/ 389 ******************************************************************************/
390 390
391static void 391static void
392nv84_fifo_uevent_enable(struct nouveau_event *event, int index) 392nv84_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
393{ 393{
394 struct nv84_fifo_priv *priv = event->priv; 394 struct nv84_fifo_priv *priv = event->priv;
395 nv_mask(priv, 0x002140, 0x40000000, 0x40000000); 395 nv_mask(priv, 0x002140, 0x40000000, 0x40000000);
396} 396}
397 397
398static void 398static void
399nv84_fifo_uevent_disable(struct nouveau_event *event, int index) 399nv84_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
400{ 400{
401 struct nv84_fifo_priv *priv = event->priv; 401 struct nv84_fifo_priv *priv = event->priv;
402 nv_mask(priv, 0x002140, 0x40000000, 0x00000000); 402 nv_mask(priv, 0x002140, 0x40000000, 0x00000000);
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
index fa1e719872b7..ae4a4dc5642a 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
@@ -730,7 +730,7 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
730 for (unkn = 0; unkn < 8; unkn++) { 730 for (unkn = 0; unkn < 8; unkn++) {
731 u32 ints = (intr >> (unkn * 0x04)) & inte; 731 u32 ints = (intr >> (unkn * 0x04)) & inte;
732 if (ints & 0x1) { 732 if (ints & 0x1) {
733 nouveau_event_trigger(priv->base.uevent, 0); 733 nouveau_event_trigger(priv->base.uevent, 1, 0);
734 ints &= ~1; 734 ints &= ~1;
735 } 735 }
736 if (ints) { 736 if (ints) {
@@ -827,14 +827,14 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
827} 827}
828 828
829static void 829static void
830nvc0_fifo_uevent_enable(struct nouveau_event *event, int index) 830nvc0_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
831{ 831{
832 struct nvc0_fifo_priv *priv = event->priv; 832 struct nvc0_fifo_priv *priv = event->priv;
833 nv_mask(priv, 0x002140, 0x80000000, 0x80000000); 833 nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
834} 834}
835 835
836static void 836static void
837nvc0_fifo_uevent_disable(struct nouveau_event *event, int index) 837nvc0_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
838{ 838{
839 struct nvc0_fifo_priv *priv = event->priv; 839 struct nvc0_fifo_priv *priv = event->priv;
840 nv_mask(priv, 0x002140, 0x80000000, 0x00000000); 840 nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index a9a1a9c9f9f2..298063edb92d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -859,7 +859,7 @@ nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv)
859static void 859static void
860nve0_fifo_intr_engine(struct nve0_fifo_priv *priv) 860nve0_fifo_intr_engine(struct nve0_fifo_priv *priv)
861{ 861{
862 nouveau_event_trigger(priv->base.uevent, 0); 862 nouveau_event_trigger(priv->base.uevent, 1, 0);
863} 863}
864 864
865static void 865static void
@@ -952,14 +952,14 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
952} 952}
953 953
954static void 954static void
955nve0_fifo_uevent_enable(struct nouveau_event *event, int index) 955nve0_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
956{ 956{
957 struct nve0_fifo_priv *priv = event->priv; 957 struct nve0_fifo_priv *priv = event->priv;
958 nv_mask(priv, 0x002140, 0x80000000, 0x80000000); 958 nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
959} 959}
960 960
961static void 961static void
962nve0_fifo_uevent_disable(struct nouveau_event *event, int index) 962nve0_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
963{ 963{
964 struct nve0_fifo_priv *priv = event->priv; 964 struct nve0_fifo_priv *priv = event->priv;
965 nv_mask(priv, 0x002140, 0x80000000, 0x00000000); 965 nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
index 5ce686ee729e..f3b4d9dbf23c 100644
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
@@ -124,7 +124,7 @@ nv50_software_sclass[] = {
124 ******************************************************************************/ 124 ******************************************************************************/
125 125
126static int 126static int
127nv50_software_vblsem_release(void *data, int head) 127nv50_software_vblsem_release(void *data, u32 type, int head)
128{ 128{
129 struct nv50_software_chan *chan = data; 129 struct nv50_software_chan *chan = data;
130 struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; 130 struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
@@ -183,7 +183,7 @@ nv50_software_context_ctor(struct nouveau_object *parent,
183 return -ENOMEM; 183 return -ENOMEM;
184 184
185 for (i = 0; i < chan->vblank.nr_event; i++) { 185 for (i = 0; i < chan->vblank.nr_event; i++) {
186 ret = nouveau_event_new(pdisp->vblank, i, pclass->vblank, 186 ret = nouveau_event_new(pdisp->vblank, 1, i, pclass->vblank,
187 chan, &chan->vblank.event[i]); 187 chan, &chan->vblank.event[i]);
188 if (ret) 188 if (ret)
189 return ret; 189 return ret;
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.h b/drivers/gpu/drm/nouveau/core/engine/software/nv50.h
index 2de370c21279..bb49a7a20857 100644
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.h
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.h
@@ -19,7 +19,7 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
19 19
20struct nv50_software_cclass { 20struct nv50_software_cclass {
21 struct nouveau_oclass base; 21 struct nouveau_oclass base;
22 int (*vblank)(void *, int); 22 int (*vblank)(void *, u32, int);
23}; 23};
24 24
25struct nv50_software_chan { 25struct nv50_software_chan {
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
index f9430c1bf3e5..135c20f38356 100644
--- a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
@@ -104,7 +104,7 @@ nvc0_software_sclass[] = {
104 ******************************************************************************/ 104 ******************************************************************************/
105 105
106static int 106static int
107nvc0_software_vblsem_release(void *data, int head) 107nvc0_software_vblsem_release(void *data, u32 type, int head)
108{ 108{
109 struct nv50_software_chan *chan = data; 109 struct nv50_software_chan *chan = data;
110 struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; 110 struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h
index 9c0cd73462d9..e0c812bc884f 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/class.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/class.h
@@ -295,6 +295,10 @@ struct nv04_display_scanoutpos {
295#define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f 295#define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f
296#define NV50_DISP_SOR_LVDS_SCRIPT 0x00013000 296#define NV50_DISP_SOR_LVDS_SCRIPT 0x00013000
297#define NV50_DISP_SOR_LVDS_SCRIPT_ID 0x0000ffff 297#define NV50_DISP_SOR_LVDS_SCRIPT_ID 0x0000ffff
298#define NV94_DISP_SOR_DP_PWR 0x00016000
299#define NV94_DISP_SOR_DP_PWR_STATE 0x00000001
300#define NV94_DISP_SOR_DP_PWR_STATE_OFF 0x00000000
301#define NV94_DISP_SOR_DP_PWR_STATE_ON 0x00000001
298 302
299#define NV50_DISP_DAC_MTHD 0x00020000 303#define NV50_DISP_DAC_MTHD 0x00020000
300#define NV50_DISP_DAC_MTHD_TYPE 0x0000f000 304#define NV50_DISP_DAC_MTHD_TYPE 0x0000f000
diff --git a/drivers/gpu/drm/nouveau/core/include/core/event.h b/drivers/gpu/drm/nouveau/core/include/core/event.h
index 5d539ebff3ed..ba3f1a76a815 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/event.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/event.h
@@ -12,32 +12,33 @@ struct nouveau_eventh {
12 struct nouveau_event *event; 12 struct nouveau_event *event;
13 struct list_head head; 13 struct list_head head;
14 unsigned long flags; 14 unsigned long flags;
15 u32 types;
15 int index; 16 int index;
16 int (*func)(void *, int); 17 int (*func)(void *, u32, int);
17 void *priv; 18 void *priv;
18}; 19};
19 20
20struct nouveau_event { 21struct nouveau_event {
21 spinlock_t list_lock;
22 spinlock_t refs_lock;
23
24 void *priv; 22 void *priv;
25 void (*enable)(struct nouveau_event *, int index); 23 int (*check)(struct nouveau_event *, u32 type, int index);
26 void (*disable)(struct nouveau_event *, int index); 24 void (*enable)(struct nouveau_event *, int type, int index);
25 void (*disable)(struct nouveau_event *, int type, int index);
27 26
27 int types_nr;
28 int index_nr; 28 int index_nr;
29 struct { 29
30 struct list_head list; 30 spinlock_t list_lock;
31 int refs; 31 struct list_head *list;
32 } index[]; 32 spinlock_t refs_lock;
33 int refs[];
33}; 34};
34 35
35int nouveau_event_create(int index_nr, struct nouveau_event **); 36int nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **);
36void nouveau_event_destroy(struct nouveau_event **); 37void nouveau_event_destroy(struct nouveau_event **);
37void nouveau_event_trigger(struct nouveau_event *, int index); 38void nouveau_event_trigger(struct nouveau_event *, u32 types, int index);
38 39
39int nouveau_event_new(struct nouveau_event *, int index, 40int nouveau_event_new(struct nouveau_event *, u32 types, int index,
40 int (*func)(void *, int), void *, 41 int (*func)(void *, u32, int), void *,
41 struct nouveau_eventh **); 42 struct nouveau_eventh **);
42void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **); 43void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **);
43void nouveau_event_get(struct nouveau_eventh *); 44void nouveau_event_get(struct nouveau_eventh *);
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h
index fd0c68804de3..fde842896806 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/disp.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/disp.h
@@ -6,8 +6,19 @@
6#include <core/device.h> 6#include <core/device.h>
7#include <core/event.h> 7#include <core/event.h>
8 8
9enum nvkm_hpd_event {
10 NVKM_HPD_PLUG = 1,
11 NVKM_HPD_UNPLUG = 2,
12 NVKM_HPD_IRQ = 4,
13 NVKM_HPD = (NVKM_HPD_PLUG | NVKM_HPD_UNPLUG | NVKM_HPD_IRQ)
14};
15
9struct nouveau_disp { 16struct nouveau_disp {
10 struct nouveau_engine base; 17 struct nouveau_engine base;
18
19 struct list_head outp;
20 struct nouveau_event *hpd;
21
11 struct nouveau_event *vblank; 22 struct nouveau_event *vblank;
12}; 23};
13 24
@@ -17,25 +28,6 @@ nouveau_disp(void *obj)
17 return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP]; 28 return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP];
18} 29}
19 30
20#define nouveau_disp_create(p,e,c,h,i,x,d) \
21 nouveau_disp_create_((p), (e), (c), (h), (i), (x), \
22 sizeof(**d), (void **)d)
23#define nouveau_disp_destroy(d) ({ \
24 struct nouveau_disp *disp = (d); \
25 _nouveau_disp_dtor(nv_object(disp)); \
26})
27#define nouveau_disp_init(d) \
28 nouveau_engine_init(&(d)->base)
29#define nouveau_disp_fini(d,s) \
30 nouveau_engine_fini(&(d)->base, (s))
31
32int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *,
33 struct nouveau_oclass *, int heads,
34 const char *, const char *, int, void **);
35void _nouveau_disp_dtor(struct nouveau_object *);
36#define _nouveau_disp_init _nouveau_engine_init
37#define _nouveau_disp_fini _nouveau_engine_fini
38
39extern struct nouveau_oclass *nv04_disp_oclass; 31extern struct nouveau_oclass *nv04_disp_oclass;
40extern struct nouveau_oclass *nv50_disp_oclass; 32extern struct nouveau_oclass *nv50_disp_oclass;
41extern struct nouveau_oclass *nv84_disp_oclass; 33extern struct nouveau_oclass *nv84_disp_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h
index a32feb3f3fb6..f3930c27cb7a 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h
@@ -22,7 +22,25 @@ enum dcb_connector_type {
22 DCB_CONNECTOR_NONE = 0xff 22 DCB_CONNECTOR_NONE = 0xff
23}; 23};
24 24
25u16 dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); 25struct nvbios_connT {
26u16 dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len); 26};
27
28u32 nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
29u32 nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
30 struct nvbios_connT *info);
31
32struct nvbios_connE {
33 u8 type;
34 u8 location;
35 u8 hpd;
36 u8 dp;
37 u8 di;
38 u8 sr;
39 u8 lcdid;
40};
41
42u32 nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr);
43u32 nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr,
44 struct nvbios_connE *info);
27 45
28#endif 46#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
index 6e54218b55fc..728206e21777 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
@@ -17,9 +17,10 @@ u16 nvbios_dpout_match(struct nouveau_bios *, u16 type, u16 mask,
17 struct nvbios_dpout *); 17 struct nvbios_dpout *);
18 18
19struct nvbios_dpcfg { 19struct nvbios_dpcfg {
20 u8 drv; 20 u8 pc;
21 u8 pre; 21 u8 dc;
22 u8 unk; 22 u8 pe;
23 u8 tx_pu;
23}; 24};
24 25
25u16 26u16
@@ -27,7 +28,7 @@ nvbios_dpcfg_parse(struct nouveau_bios *, u16 outp, u8 idx,
27 u8 *ver, u8 *hdr, u8 *cnt, u8 *len, 28 u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
28 struct nvbios_dpcfg *); 29 struct nvbios_dpcfg *);
29u16 30u16
30nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 un, u8 vs, u8 pe, 31nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 pc, u8 vs, u8 pe,
31 u8 *ver, u8 *hdr, u8 *cnt, u8 *len, 32 u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
32 struct nvbios_dpcfg *); 33 struct nvbios_dpcfg *);
33 34
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
index c85b9f1579ad..612d82ab683d 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
@@ -8,17 +8,18 @@
8#include <subdev/bios.h> 8#include <subdev/bios.h>
9#include <subdev/bios/gpio.h> 9#include <subdev/bios/gpio.h>
10 10
11enum nvkm_gpio_event {
12 NVKM_GPIO_HI = 1,
13 NVKM_GPIO_LO = 2,
14 NVKM_GPIO_TOGGLED = (NVKM_GPIO_HI | NVKM_GPIO_LO),
15};
16
11struct nouveau_gpio { 17struct nouveau_gpio {
12 struct nouveau_subdev base; 18 struct nouveau_subdev base;
13 19
14 struct nouveau_event *events; 20 struct nouveau_event *events;
15 21
16 /* hardware interfaces */
17 void (*reset)(struct nouveau_gpio *, u8 func); 22 void (*reset)(struct nouveau_gpio *, u8 func);
18 int (*drive)(struct nouveau_gpio *, int line, int dir, int out);
19 int (*sense)(struct nouveau_gpio *, int line);
20
21 /* software interfaces */
22 int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line, 23 int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
23 struct dcb_gpio_func *); 24 struct dcb_gpio_func *);
24 int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state); 25 int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state);
@@ -31,23 +32,10 @@ nouveau_gpio(void *obj)
31 return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO]; 32 return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO];
32} 33}
33 34
34#define nouveau_gpio_create(p,e,o,l,d) \ 35extern struct nouveau_oclass *nv10_gpio_oclass;
35 nouveau_gpio_create_((p), (e), (o), (l), sizeof(**d), (void **)d) 36extern struct nouveau_oclass *nv50_gpio_oclass;
36#define nouveau_gpio_destroy(p) ({ \ 37extern struct nouveau_oclass *nv92_gpio_oclass;
37 struct nouveau_gpio *gpio = (p); \ 38extern struct nouveau_oclass *nvd0_gpio_oclass;
38 _nouveau_gpio_dtor(nv_object(gpio)); \ 39extern struct nouveau_oclass *nve0_gpio_oclass;
39})
40#define nouveau_gpio_fini(p,s) \
41 nouveau_subdev_fini(&(p)->base, (s))
42
43int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
44 struct nouveau_oclass *, int, int, void **);
45void _nouveau_gpio_dtor(struct nouveau_object *);
46int nouveau_gpio_init(struct nouveau_gpio *);
47
48extern struct nouveau_oclass nv10_gpio_oclass;
49extern struct nouveau_oclass nv50_gpio_oclass;
50extern struct nouveau_oclass nvd0_gpio_oclass;
51extern struct nouveau_oclass nve0_gpio_oclass;
52 40
53#endif 41#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
index 7f50a858b16f..db1b39d08013 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
@@ -14,52 +14,41 @@
14#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8) 14#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
15#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8) 15#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
16 16
17enum nvkm_i2c_event {
18 NVKM_I2C_PLUG = 1,
19 NVKM_I2C_UNPLUG = 2,
20 NVKM_I2C_IRQ = 4,
21 NVKM_I2C_DONE = 8,
22 NVKM_I2C_ANY = (NVKM_I2C_PLUG |
23 NVKM_I2C_UNPLUG |
24 NVKM_I2C_IRQ |
25 NVKM_I2C_DONE),
26};
27
17struct nouveau_i2c_port { 28struct nouveau_i2c_port {
18 struct nouveau_object base; 29 struct nouveau_object base;
19 struct i2c_adapter adapter; 30 struct i2c_adapter adapter;
31 struct mutex mutex;
20 32
21 struct list_head head; 33 struct list_head head;
22 u8 index; 34 u8 index;
35 int aux;
23 36
24 const struct nouveau_i2c_func *func; 37 const struct nouveau_i2c_func *func;
25}; 38};
26 39
27struct nouveau_i2c_func { 40struct nouveau_i2c_func {
28 void (*acquire)(struct nouveau_i2c_port *);
29 void (*release)(struct nouveau_i2c_port *);
30
31 void (*drive_scl)(struct nouveau_i2c_port *, int); 41 void (*drive_scl)(struct nouveau_i2c_port *, int);
32 void (*drive_sda)(struct nouveau_i2c_port *, int); 42 void (*drive_sda)(struct nouveau_i2c_port *, int);
33 int (*sense_scl)(struct nouveau_i2c_port *); 43 int (*sense_scl)(struct nouveau_i2c_port *);
34 int (*sense_sda)(struct nouveau_i2c_port *); 44 int (*sense_sda)(struct nouveau_i2c_port *);
35 45
36 int (*aux)(struct nouveau_i2c_port *, u8, u32, u8 *, u8); 46 int (*aux)(struct nouveau_i2c_port *, bool, u8, u32, u8 *, u8);
37 int (*pattern)(struct nouveau_i2c_port *, int pattern); 47 int (*pattern)(struct nouveau_i2c_port *, int pattern);
38 int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh); 48 int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh);
39 int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe); 49 int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
40}; 50};
41 51
42#define nouveau_i2c_port_create(p,e,o,i,a,f,d) \
43 nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f), \
44 sizeof(**d), (void **)d)
45#define nouveau_i2c_port_destroy(p) ({ \
46 struct nouveau_i2c_port *port = (p); \
47 _nouveau_i2c_port_dtor(nv_object(i2c)); \
48})
49#define nouveau_i2c_port_init(p) \
50 nouveau_object_init(&(p)->base)
51#define nouveau_i2c_port_fini(p,s) \
52 nouveau_object_fini(&(p)->base, (s))
53
54int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *,
55 struct nouveau_oclass *, u8,
56 const struct i2c_algorithm *,
57 const struct nouveau_i2c_func *,
58 int, void **);
59void _nouveau_i2c_port_dtor(struct nouveau_object *);
60#define _nouveau_i2c_port_init nouveau_object_init
61#define _nouveau_i2c_port_fini nouveau_object_fini
62
63struct nouveau_i2c_board_info { 52struct nouveau_i2c_board_info {
64 struct i2c_board_info dev; 53 struct i2c_board_info dev;
65 u8 udelay; /* set to 0 to use the standard delay */ 54 u8 udelay; /* set to 0 to use the standard delay */
@@ -67,13 +56,20 @@ struct nouveau_i2c_board_info {
67 56
68struct nouveau_i2c { 57struct nouveau_i2c {
69 struct nouveau_subdev base; 58 struct nouveau_subdev base;
59 struct nouveau_event *ntfy;
70 60
71 struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); 61 struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
72 struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); 62 struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
63 int (*acquire_pad)(struct nouveau_i2c_port *, unsigned long timeout);
64 void (*release_pad)(struct nouveau_i2c_port *);
65 int (*acquire)(struct nouveau_i2c_port *, unsigned long timeout);
66 void (*release)(struct nouveau_i2c_port *);
73 int (*identify)(struct nouveau_i2c *, int index, 67 int (*identify)(struct nouveau_i2c *, int index,
74 const char *what, struct nouveau_i2c_board_info *, 68 const char *what, struct nouveau_i2c_board_info *,
75 bool (*match)(struct nouveau_i2c_port *, 69 bool (*match)(struct nouveau_i2c_port *,
76 struct i2c_board_info *, void *), void *); 70 struct i2c_board_info *, void *), void *);
71
72 wait_queue_head_t wait;
77 struct list_head ports; 73 struct list_head ports;
78}; 74};
79 75
@@ -83,37 +79,12 @@ nouveau_i2c(void *obj)
83 return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C]; 79 return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C];
84} 80}
85 81
86#define nouveau_i2c_create(p,e,o,s,d) \ 82extern struct nouveau_oclass *nv04_i2c_oclass;
87 nouveau_i2c_create_((p), (e), (o), (s), sizeof(**d), (void **)d) 83extern struct nouveau_oclass *nv4e_i2c_oclass;
88#define nouveau_i2c_destroy(p) ({ \ 84extern struct nouveau_oclass *nv50_i2c_oclass;
89 struct nouveau_i2c *i2c = (p); \ 85extern struct nouveau_oclass *nv94_i2c_oclass;
90 _nouveau_i2c_dtor(nv_object(i2c)); \ 86extern struct nouveau_oclass *nvd0_i2c_oclass;
91}) 87extern struct nouveau_oclass *nve0_i2c_oclass;
92#define nouveau_i2c_init(p) ({ \
93 struct nouveau_i2c *i2c = (p); \
94 _nouveau_i2c_init(nv_object(i2c)); \
95})
96#define nouveau_i2c_fini(p,s) ({ \
97 struct nouveau_i2c *i2c = (p); \
98 _nouveau_i2c_fini(nv_object(i2c), (s)); \
99})
100
101int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *,
102 struct nouveau_oclass *, struct nouveau_oclass *,
103 int, void **);
104void _nouveau_i2c_dtor(struct nouveau_object *);
105int _nouveau_i2c_init(struct nouveau_object *);
106int _nouveau_i2c_fini(struct nouveau_object *, bool);
107
108extern struct nouveau_oclass nv04_i2c_oclass;
109extern struct nouveau_oclass nv4e_i2c_oclass;
110extern struct nouveau_oclass nv50_i2c_oclass;
111extern struct nouveau_oclass nv94_i2c_oclass;
112extern struct nouveau_oclass nvd0_i2c_oclass;
113extern struct nouveau_oclass nouveau_anx9805_sclass[];
114
115extern const struct i2c_algorithm nouveau_i2c_bit_algo;
116extern const struct i2c_algorithm nouveau_i2c_aux_algo;
117 88
118static inline int 89static inline int
119nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg) 90nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c b/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c
index 5ac010efd959..2ede3bcd96a1 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c
@@ -28,12 +28,12 @@
28#include <subdev/bios/dcb.h> 28#include <subdev/bios/dcb.h>
29#include <subdev/bios/conn.h> 29#include <subdev/bios/conn.h>
30 30
31u16 31u32
32dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) 32nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
33{ 33{
34 u16 dcb = dcb_table(bios, ver, hdr, cnt, len); 34 u32 dcb = dcb_table(bios, ver, hdr, cnt, len);
35 if (dcb && *ver >= 0x30 && *hdr >= 0x16) { 35 if (dcb && *ver >= 0x30 && *hdr >= 0x16) {
36 u16 data = nv_ro16(bios, dcb + 0x14); 36 u32 data = nv_ro16(bios, dcb + 0x14);
37 if (data) { 37 if (data) {
38 *ver = nv_ro08(bios, data + 0); 38 *ver = nv_ro08(bios, data + 0);
39 *hdr = nv_ro08(bios, data + 1); 39 *hdr = nv_ro08(bios, data + 1);
@@ -42,15 +42,59 @@ dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
42 return data; 42 return data;
43 } 43 }
44 } 44 }
45 return 0x0000; 45 return 0x00000000;
46} 46}
47 47
48u16 48u32
49dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) 49nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
50 struct nvbios_connT *info)
51{
52 u32 data = nvbios_connTe(bios, ver, hdr, cnt, len);
53 memset(info, 0x00, sizeof(*info));
54 switch (!!data * *ver) {
55 case 0x30:
56 case 0x40:
57 return data;
58 default:
59 break;
60 }
61 return 0x00000000;
62}
63
64u32
65nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
50{ 66{
51 u8 hdr, cnt; 67 u8 hdr, cnt;
52 u16 data = dcb_conntab(bios, ver, &hdr, &cnt, len); 68 u32 data = nvbios_connTe(bios, ver, &hdr, &cnt, len);
53 if (data && idx < cnt) 69 if (data && idx < cnt)
54 return data + hdr + (idx * *len); 70 return data + hdr + (idx * *len);
55 return 0x0000; 71 return 0x00000000;
72}
73
74u32
75nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
76 struct nvbios_connE *info)
77{
78 u32 data = nvbios_connEe(bios, idx, ver, len);
79 memset(info, 0x00, sizeof(*info));
80 switch (!!data * *ver) {
81 case 0x30:
82 case 0x40:
83 info->type = nv_ro08(bios, data + 0x00);
84 info->location = nv_ro08(bios, data + 0x01) & 0x0f;
85 info->hpd = (nv_ro08(bios, data + 0x01) & 0x30) >> 4;
86 info->dp = (nv_ro08(bios, data + 0x01) & 0xc0) >> 6;
87 if (*len < 4)
88 return data;
89 info->hpd |= (nv_ro08(bios, data + 0x02) & 0x03) << 2;
90 info->dp |= nv_ro08(bios, data + 0x02) & 0x0c;
91 info->di = (nv_ro08(bios, data + 0x02) & 0xf0) >> 4;
92 info->hpd |= (nv_ro08(bios, data + 0x03) & 0x07) << 4;
93 info->sr = (nv_ro08(bios, data + 0x03) & 0x08) >> 3;
94 info->lcdid = (nv_ro08(bios, data + 0x03) & 0x70) >> 4;
95 return data;
96 default:
97 break;
98 }
99 return 0x00000000;
56} 100}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
index 7628fe759220..f309dd657250 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
@@ -162,18 +162,20 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
162 struct nvbios_dpcfg *info) 162 struct nvbios_dpcfg *info)
163{ 163{
164 u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len); 164 u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len);
165 memset(info, 0x00, sizeof(*info));
165 if (data) { 166 if (data) {
166 switch (*ver) { 167 switch (*ver) {
167 case 0x21: 168 case 0x21:
168 info->drv = nv_ro08(bios, data + 0x02); 169 info->dc = nv_ro08(bios, data + 0x02);
169 info->pre = nv_ro08(bios, data + 0x03); 170 info->pe = nv_ro08(bios, data + 0x03);
170 info->unk = nv_ro08(bios, data + 0x04); 171 info->tx_pu = nv_ro08(bios, data + 0x04);
171 break; 172 break;
172 case 0x30: 173 case 0x30:
173 case 0x40: 174 case 0x40:
174 info->drv = nv_ro08(bios, data + 0x01); 175 info->pc = nv_ro08(bios, data + 0x00);
175 info->pre = nv_ro08(bios, data + 0x02); 176 info->dc = nv_ro08(bios, data + 0x01);
176 info->unk = nv_ro08(bios, data + 0x03); 177 info->pe = nv_ro08(bios, data + 0x02);
178 info->tx_pu = nv_ro08(bios, data + 0x03);
177 break; 179 break;
178 default: 180 default:
179 data = 0x0000; 181 data = 0x0000;
@@ -184,7 +186,7 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
184} 186}
185 187
186u16 188u16
187nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe, 189nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
188 u8 *ver, u8 *hdr, u8 *cnt, u8 *len, 190 u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
189 struct nvbios_dpcfg *info) 191 struct nvbios_dpcfg *info)
190{ 192{
@@ -193,16 +195,15 @@ nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe,
193 195
194 if (*ver >= 0x30) { 196 if (*ver >= 0x30) {
195 const u8 vsoff[] = { 0, 4, 7, 9 }; 197 const u8 vsoff[] = { 0, 4, 7, 9 };
196 idx = (un * 10) + vsoff[vs] + pe; 198 idx = (pc * 10) + vsoff[vs] + pe;
197 } else { 199 } else {
198 while ((data = nvbios_dpcfg_entry(bios, outp, idx, 200 while ((data = nvbios_dpcfg_entry(bios, outp, ++idx,
199 ver, hdr, cnt, len))) { 201 ver, hdr, cnt, len))) {
200 if (nv_ro08(bios, data + 0x00) == vs && 202 if (nv_ro08(bios, data + 0x00) == vs &&
201 nv_ro08(bios, data + 0x01) == pe) 203 nv_ro08(bios, data + 0x01) == pe)
202 break; 204 break;
203 idx++;
204 } 205 }
205 } 206 }
206 207
207 return nvbios_dpcfg_parse(bios, outp, pe, ver, hdr, cnt, len, info); 208 return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info);
208} 209}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
index acaeaf79e3f0..626380f9e4c0 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
@@ -98,15 +98,16 @@ static u8
98init_conn(struct nvbios_init *init) 98init_conn(struct nvbios_init *init)
99{ 99{
100 struct nouveau_bios *bios = init->bios; 100 struct nouveau_bios *bios = init->bios;
101 u8 ver, len; 101 struct nvbios_connE connE;
102 u16 conn; 102 u8 ver, hdr;
103 u32 conn;
103 104
104 if (init_exec(init)) { 105 if (init_exec(init)) {
105 if (init->outp) { 106 if (init->outp) {
106 conn = init->outp->connector; 107 conn = init->outp->connector;
107 conn = dcb_conn(bios, conn, &ver, &len); 108 conn = nvbios_connEp(bios, conn, &ver, &hdr, &connE);
108 if (conn) 109 if (conn)
109 return nv_ro08(bios, conn); 110 return connE.type;
110 } 111 }
111 112
112 error("script needs connector type\n"); 113 error("script needs connector type\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
index f572c2804c32..45e0202f3151 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
@@ -22,21 +22,24 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24 24
25#include <subdev/gpio.h>
26#include <subdev/bios.h> 25#include <subdev/bios.h>
27#include <subdev/bios/gpio.h> 26#include <subdev/bios/gpio.h>
28 27
28#include "priv.h"
29
29static int 30static int
30nouveau_gpio_drive(struct nouveau_gpio *gpio, 31nouveau_gpio_drive(struct nouveau_gpio *gpio,
31 int idx, int line, int dir, int out) 32 int idx, int line, int dir, int out)
32{ 33{
33 return gpio->drive ? gpio->drive(gpio, line, dir, out) : -ENODEV; 34 const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
35 return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV;
34} 36}
35 37
36static int 38static int
37nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line) 39nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line)
38{ 40{
39 return gpio->sense ? gpio->sense(gpio, line) : -ENODEV; 41 const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
42 return impl->sense ? impl->sense(gpio, line) : -ENODEV;
40} 43}
41 44
42static int 45static int
@@ -102,6 +105,80 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
102 return ret; 105 return ret;
103} 106}
104 107
108static void
109nouveau_gpio_intr_disable(struct nouveau_event *event, int type, int index)
110{
111 struct nouveau_gpio *gpio = nouveau_gpio(event->priv);
112 const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
113 impl->intr_mask(gpio, type, 1 << index, 0);
114}
115
116static void
117nouveau_gpio_intr_enable(struct nouveau_event *event, int type, int index)
118{
119 struct nouveau_gpio *gpio = nouveau_gpio(event->priv);
120 const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
121 impl->intr_mask(gpio, type, 1 << index, 1 << index);
122}
123
124static void
125nouveau_gpio_intr(struct nouveau_subdev *subdev)
126{
127 struct nouveau_gpio *gpio = nouveau_gpio(subdev);
128 const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
129 u32 hi, lo, e, i;
130
131 impl->intr_stat(gpio, &hi, &lo);
132
133 for (i = 0; e = 0, (hi | lo) && i < impl->lines; i++) {
134 if (hi & (1 << i))
135 e |= NVKM_GPIO_HI;
136 if (lo & (1 << i))
137 e |= NVKM_GPIO_LO;
138 nouveau_event_trigger(gpio->events, e, i);
139 }
140}
141
142int
143_nouveau_gpio_fini(struct nouveau_object *object, bool suspend)
144{
145 const struct nouveau_gpio_impl *impl = (void *)object->oclass;
146 struct nouveau_gpio *gpio = nouveau_gpio(object);
147 u32 mask = (1 << impl->lines) - 1;
148
149 impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0);
150 impl->intr_stat(gpio, &mask, &mask);
151
152 return nouveau_subdev_fini(&gpio->base, suspend);
153}
154
155static struct dmi_system_id gpio_reset_ids[] = {
156 {
157 .ident = "Apple Macbook 10,1",
158 .matches = {
159 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
160 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
161 }
162 },
163 { }
164};
165
166int
167_nouveau_gpio_init(struct nouveau_object *object)
168{
169 struct nouveau_gpio *gpio = nouveau_gpio(object);
170 int ret;
171
172 ret = nouveau_subdev_init(&gpio->base);
173 if (ret)
174 return ret;
175
176 if (gpio->reset && dmi_check_system(gpio_reset_ids))
177 gpio->reset(gpio, DCB_GPIO_UNUSED);
178
179 return ret;
180}
181
105void 182void
106_nouveau_gpio_dtor(struct nouveau_object *object) 183_nouveau_gpio_dtor(struct nouveau_object *object)
107{ 184{
@@ -113,9 +190,10 @@ _nouveau_gpio_dtor(struct nouveau_object *object)
113int 190int
114nouveau_gpio_create_(struct nouveau_object *parent, 191nouveau_gpio_create_(struct nouveau_object *parent,
115 struct nouveau_object *engine, 192 struct nouveau_object *engine,
116 struct nouveau_oclass *oclass, int lines, 193 struct nouveau_oclass *oclass,
117 int length, void **pobject) 194 int length, void **pobject)
118{ 195{
196 const struct nouveau_gpio_impl *impl = (void *)oclass;
119 struct nouveau_gpio *gpio; 197 struct nouveau_gpio *gpio;
120 int ret; 198 int ret;
121 199
@@ -125,34 +203,34 @@ nouveau_gpio_create_(struct nouveau_object *parent,
125 if (ret) 203 if (ret)
126 return ret; 204 return ret;
127 205
128 ret = nouveau_event_create(lines, &gpio->events);
129 if (ret)
130 return ret;
131
132 gpio->find = nouveau_gpio_find; 206 gpio->find = nouveau_gpio_find;
133 gpio->set = nouveau_gpio_set; 207 gpio->set = nouveau_gpio_set;
134 gpio->get = nouveau_gpio_get; 208 gpio->get = nouveau_gpio_get;
209 gpio->reset = impl->reset;
210
211 ret = nouveau_event_create(2, impl->lines, &gpio->events);
212 if (ret)
213 return ret;
214
215 gpio->events->priv = gpio;
216 gpio->events->enable = nouveau_gpio_intr_enable;
217 gpio->events->disable = nouveau_gpio_intr_disable;
218 nv_subdev(gpio)->intr = nouveau_gpio_intr;
135 return 0; 219 return 0;
136} 220}
137 221
138static struct dmi_system_id gpio_reset_ids[] = {
139 {
140 .ident = "Apple Macbook 10,1",
141 .matches = {
142 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
143 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
144 }
145 },
146 { }
147};
148
149int 222int
150nouveau_gpio_init(struct nouveau_gpio *gpio) 223_nouveau_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
224 struct nouveau_oclass *oclass, void *data, u32 size,
225 struct nouveau_object **pobject)
151{ 226{
152 int ret = nouveau_subdev_init(&gpio->base); 227 struct nouveau_gpio *gpio;
153 if (ret == 0 && gpio->reset) { 228 int ret;
154 if (dmi_check_system(gpio_reset_ids)) 229
155 gpio->reset(gpio, DCB_GPIO_UNUSED); 230 ret = nouveau_gpio_create(parent, engine, oclass, &gpio);
156 } 231 *pobject = nv_object(gpio);
157 return ret; 232 if (ret)
233 return ret;
234
235 return 0;
158} 236}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
index 76d5d5465ddd..27ad23eaf185 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
@@ -26,10 +26,6 @@
26 26
27#include "priv.h" 27#include "priv.h"
28 28
29struct nv10_gpio_priv {
30 struct nouveau_gpio base;
31};
32
33static int 29static int
34nv10_gpio_sense(struct nouveau_gpio *gpio, int line) 30nv10_gpio_sense(struct nouveau_gpio *gpio, int line)
35{ 31{
@@ -83,95 +79,38 @@ nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
83} 79}
84 80
85static void 81static void
86nv10_gpio_intr(struct nouveau_subdev *subdev) 82nv10_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
87{
88 struct nv10_gpio_priv *priv = (void *)subdev;
89 u32 intr = nv_rd32(priv, 0x001104);
90 u32 hi = (intr & 0x0000ffff) >> 0;
91 u32 lo = (intr & 0xffff0000) >> 16;
92 int i;
93
94 for (i = 0; (hi | lo) && i < 32; i++) {
95 if ((hi | lo) & (1 << i))
96 nouveau_event_trigger(priv->base.events, i);
97 }
98
99 nv_wr32(priv, 0x001104, intr);
100}
101
102static void
103nv10_gpio_intr_enable(struct nouveau_event *event, int line)
104{
105 nv_wr32(event->priv, 0x001104, 0x00010001 << line);
106 nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00010001 << line);
107}
108
109static void
110nv10_gpio_intr_disable(struct nouveau_event *event, int line)
111{
112 nv_wr32(event->priv, 0x001104, 0x00010001 << line);
113 nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00000000);
114}
115
116static int
117nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
118 struct nouveau_oclass *oclass, void *data, u32 size,
119 struct nouveau_object **pobject)
120{ 83{
121 struct nv10_gpio_priv *priv; 84 u32 intr = nv_rd32(gpio, 0x001104);
122 int ret; 85 u32 stat = nv_rd32(gpio, 0x001144) & intr;
123 86 *lo = (stat & 0xffff0000) >> 16;
124 ret = nouveau_gpio_create(parent, engine, oclass, 16, &priv); 87 *hi = (stat & 0x0000ffff);
125 *pobject = nv_object(priv); 88 nv_wr32(gpio, 0x001104, intr);
126 if (ret)
127 return ret;
128
129 priv->base.drive = nv10_gpio_drive;
130 priv->base.sense = nv10_gpio_sense;
131 priv->base.events->priv = priv;
132 priv->base.events->enable = nv10_gpio_intr_enable;
133 priv->base.events->disable = nv10_gpio_intr_disable;
134 nv_subdev(priv)->intr = nv10_gpio_intr;
135 return 0;
136} 89}
137 90
138static void 91static void
139nv10_gpio_dtor(struct nouveau_object *object) 92nv10_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
140{
141 struct nv10_gpio_priv *priv = (void *)object;
142 nouveau_gpio_destroy(&priv->base);
143}
144
145static int
146nv10_gpio_init(struct nouveau_object *object)
147{
148 struct nv10_gpio_priv *priv = (void *)object;
149 int ret;
150
151 ret = nouveau_gpio_init(&priv->base);
152 if (ret)
153 return ret;
154
155 nv_wr32(priv, 0x001144, 0x00000000);
156 nv_wr32(priv, 0x001104, 0xffffffff);
157 return 0;
158}
159
160static int
161nv10_gpio_fini(struct nouveau_object *object, bool suspend)
162{ 93{
163 struct nv10_gpio_priv *priv = (void *)object; 94 u32 inte = nv_rd32(gpio, 0x001144);
164 nv_wr32(priv, 0x001144, 0x00000000); 95 if (type & NVKM_GPIO_LO)
165 return nouveau_gpio_fini(&priv->base, suspend); 96 inte = (inte & ~(mask << 16)) | (data << 16);
97 if (type & NVKM_GPIO_HI)
98 inte = (inte & ~mask) | data;
99 nv_wr32(gpio, 0x001144, inte);
166} 100}
167 101
168struct nouveau_oclass 102struct nouveau_oclass *
169nv10_gpio_oclass = { 103nv10_gpio_oclass = &(struct nouveau_gpio_impl) {
170 .handle = NV_SUBDEV(GPIO, 0x10), 104 .base.handle = NV_SUBDEV(GPIO, 0x10),
171 .ofuncs = &(struct nouveau_ofuncs) { 105 .base.ofuncs = &(struct nouveau_ofuncs) {
172 .ctor = nv10_gpio_ctor, 106 .ctor = _nouveau_gpio_ctor,
173 .dtor = nv10_gpio_dtor, 107 .dtor = _nouveau_gpio_dtor,
174 .init = nv10_gpio_init, 108 .init = _nouveau_gpio_init,
175 .fini = nv10_gpio_fini, 109 .fini = _nouveau_gpio_fini,
176 }, 110 },
177}; 111 .lines = 16,
112 .intr_stat = nv10_gpio_intr_stat,
113 .intr_mask = nv10_gpio_intr_mask,
114 .drive = nv10_gpio_drive,
115 .sense = nv10_gpio_sense,
116}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
index 2ef774731629..1864fa98e6b1 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
@@ -24,15 +24,10 @@
24 24
25#include "priv.h" 25#include "priv.h"
26 26
27struct nv50_gpio_priv { 27void
28 struct nouveau_gpio base;
29};
30
31static void
32nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) 28nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
33{ 29{
34 struct nouveau_bios *bios = nouveau_bios(gpio); 30 struct nouveau_bios *bios = nouveau_bios(gpio);
35 struct nv50_gpio_priv *priv = (void *)gpio;
36 u8 ver, len; 31 u8 ver, len;
37 u16 entry; 32 u16 entry;
38 int ent = -1; 33 int ent = -1;
@@ -55,7 +50,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
55 50
56 gpio->set(gpio, 0, func, line, defs); 51 gpio->set(gpio, 0, func, line, defs);
57 52
58 nv_mask(priv, reg, 0x00010001 << lsh, val << lsh); 53 nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh);
59 } 54 }
60} 55}
61 56
@@ -72,7 +67,7 @@ nv50_gpio_location(int line, u32 *reg, u32 *shift)
72 return 0; 67 return 0;
73} 68}
74 69
75static int 70int
76nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) 71nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
77{ 72{
78 u32 reg, shift; 73 u32 reg, shift;
@@ -84,7 +79,7 @@ nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
84 return 0; 79 return 0;
85} 80}
86 81
87static int 82int
88nv50_gpio_sense(struct nouveau_gpio *gpio, int line) 83nv50_gpio_sense(struct nouveau_gpio *gpio, int line)
89{ 84{
90 u32 reg, shift; 85 u32 reg, shift;
@@ -95,119 +90,40 @@ nv50_gpio_sense(struct nouveau_gpio *gpio, int line)
95 return !!(nv_rd32(gpio, reg) & (4 << shift)); 90 return !!(nv_rd32(gpio, reg) & (4 << shift));
96} 91}
97 92
98void 93static void
99nv50_gpio_intr(struct nouveau_subdev *subdev) 94nv50_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
100{
101 struct nv50_gpio_priv *priv = (void *)subdev;
102 u32 intr0, intr1 = 0;
103 u32 hi, lo;
104 int i;
105
106 intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
107 if (nv_device(priv)->chipset > 0x92)
108 intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);
109
110 hi = (intr0 & 0x0000ffff) | (intr1 << 16);
111 lo = (intr0 >> 16) | (intr1 & 0xffff0000);
112
113 for (i = 0; (hi | lo) && i < 32; i++) {
114 if ((hi | lo) & (1 << i))
115 nouveau_event_trigger(priv->base.events, i);
116 }
117
118 nv_wr32(priv, 0xe054, intr0);
119 if (nv_device(priv)->chipset > 0x92)
120 nv_wr32(priv, 0xe074, intr1);
121}
122
123void
124nv50_gpio_intr_enable(struct nouveau_event *event, int line)
125{
126 const u32 addr = line < 16 ? 0xe050 : 0xe070;
127 const u32 mask = 0x00010001 << (line & 0xf);
128 nv_wr32(event->priv, addr + 0x04, mask);
129 nv_mask(event->priv, addr + 0x00, mask, mask);
130}
131
132void
133nv50_gpio_intr_disable(struct nouveau_event *event, int line)
134{
135 const u32 addr = line < 16 ? 0xe050 : 0xe070;
136 const u32 mask = 0x00010001 << (line & 0xf);
137 nv_wr32(event->priv, addr + 0x04, mask);
138 nv_mask(event->priv, addr + 0x00, mask, 0x00000000);
139}
140
141static int
142nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
143 struct nouveau_oclass *oclass, void *data, u32 size,
144 struct nouveau_object **pobject)
145{
146 struct nv50_gpio_priv *priv;
147 int ret;
148
149 ret = nouveau_gpio_create(parent, engine, oclass,
150 nv_device(parent)->chipset > 0x92 ? 32 : 16,
151 &priv);
152 *pobject = nv_object(priv);
153 if (ret)
154 return ret;
155
156 priv->base.reset = nv50_gpio_reset;
157 priv->base.drive = nv50_gpio_drive;
158 priv->base.sense = nv50_gpio_sense;
159 priv->base.events->priv = priv;
160 priv->base.events->enable = nv50_gpio_intr_enable;
161 priv->base.events->disable = nv50_gpio_intr_disable;
162 nv_subdev(priv)->intr = nv50_gpio_intr;
163 return 0;
164}
165
166void
167nv50_gpio_dtor(struct nouveau_object *object)
168{
169 struct nv50_gpio_priv *priv = (void *)object;
170 nouveau_gpio_destroy(&priv->base);
171}
172
173int
174nv50_gpio_init(struct nouveau_object *object)
175{ 95{
176 struct nv50_gpio_priv *priv = (void *)object; 96 u32 intr = nv_rd32(gpio, 0x00e054);
177 int ret; 97 u32 stat = nv_rd32(gpio, 0x00e050) & intr;
178 98 *lo = (stat & 0xffff0000) >> 16;
179 ret = nouveau_gpio_init(&priv->base); 99 *hi = (stat & 0x0000ffff);
180 if (ret) 100 nv_wr32(gpio, 0x00e054, intr);
181 return ret;
182
183 /* disable, and ack any pending gpio interrupts */
184 nv_wr32(priv, 0xe050, 0x00000000);
185 nv_wr32(priv, 0xe054, 0xffffffff);
186 if (nv_device(priv)->chipset > 0x92) {
187 nv_wr32(priv, 0xe070, 0x00000000);
188 nv_wr32(priv, 0xe074, 0xffffffff);
189 }
190
191 return 0;
192} 101}
193 102
194int 103static void
195nv50_gpio_fini(struct nouveau_object *object, bool suspend) 104nv50_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
196{ 105{
197 struct nv50_gpio_priv *priv = (void *)object; 106 u32 inte = nv_rd32(gpio, 0x00e050);
198 nv_wr32(priv, 0xe050, 0x00000000); 107 if (type & NVKM_GPIO_LO)
199 if (nv_device(priv)->chipset > 0x92) 108 inte = (inte & ~(mask << 16)) | (data << 16);
200 nv_wr32(priv, 0xe070, 0x00000000); 109 if (type & NVKM_GPIO_HI)
201 return nouveau_gpio_fini(&priv->base, suspend); 110 inte = (inte & ~mask) | data;
111 nv_wr32(gpio, 0x00e050, inte);
202} 112}
203 113
204struct nouveau_oclass 114struct nouveau_oclass *
205nv50_gpio_oclass = { 115nv50_gpio_oclass = &(struct nouveau_gpio_impl) {
206 .handle = NV_SUBDEV(GPIO, 0x50), 116 .base.handle = NV_SUBDEV(GPIO, 0x50),
207 .ofuncs = &(struct nouveau_ofuncs) { 117 .base.ofuncs = &(struct nouveau_ofuncs) {
208 .ctor = nv50_gpio_ctor, 118 .ctor = _nouveau_gpio_ctor,
209 .dtor = nv50_gpio_dtor, 119 .dtor = _nouveau_gpio_dtor,
210 .init = nv50_gpio_init, 120 .init = _nouveau_gpio_init,
211 .fini = nv50_gpio_fini, 121 .fini = _nouveau_gpio_fini,
212 }, 122 },
213}; 123 .lines = 16,
124 .intr_stat = nv50_gpio_intr_stat,
125 .intr_mask = nv50_gpio_intr_mask,
126 .drive = nv50_gpio_drive,
127 .sense = nv50_gpio_sense,
128 .reset = nv50_gpio_reset,
129}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c
new file mode 100644
index 000000000000..252083d376f5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c
@@ -0,0 +1,74 @@
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 "priv.h"
26
27void
28nv92_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
29{
30 u32 intr0 = nv_rd32(gpio, 0x00e054);
31 u32 intr1 = nv_rd32(gpio, 0x00e074);
32 u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0;
33 u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1;
34 *lo = (stat1 & 0xffff0000) | (stat0 >> 16);
35 *hi = (stat1 << 16) | (stat0 & 0x0000ffff);
36 nv_wr32(gpio, 0x00e054, intr0);
37 nv_wr32(gpio, 0x00e074, intr1);
38}
39
40void
41nv92_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
42{
43 u32 inte0 = nv_rd32(gpio, 0x00e050);
44 u32 inte1 = nv_rd32(gpio, 0x00e070);
45 if (type & NVKM_GPIO_LO)
46 inte0 = (inte0 & ~(mask << 16)) | (data << 16);
47 if (type & NVKM_GPIO_HI)
48 inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
49 mask >>= 16;
50 data >>= 16;
51 if (type & NVKM_GPIO_LO)
52 inte1 = (inte1 & ~(mask << 16)) | (data << 16);
53 if (type & NVKM_GPIO_HI)
54 inte1 = (inte1 & ~mask) | data;
55 nv_wr32(gpio, 0x00e050, inte0);
56 nv_wr32(gpio, 0x00e070, inte1);
57}
58
59struct nouveau_oclass *
60nv92_gpio_oclass = &(struct nouveau_gpio_impl) {
61 .base.handle = NV_SUBDEV(GPIO, 0x92),
62 .base.ofuncs = &(struct nouveau_ofuncs) {
63 .ctor = _nouveau_gpio_ctor,
64 .dtor = _nouveau_gpio_dtor,
65 .init = _nouveau_gpio_init,
66 .fini = _nouveau_gpio_fini,
67 },
68 .lines = 32,
69 .intr_stat = nv92_gpio_intr_stat,
70 .intr_mask = nv92_gpio_intr_mask,
71 .drive = nv50_gpio_drive,
72 .sense = nv50_gpio_sense,
73 .reset = nv50_gpio_reset,
74}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
index 010431e3acec..a4682b0956ad 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
@@ -24,15 +24,10 @@
24 24
25#include "priv.h" 25#include "priv.h"
26 26
27struct nvd0_gpio_priv {
28 struct nouveau_gpio base;
29};
30
31void 27void
32nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match) 28nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match)
33{ 29{
34 struct nouveau_bios *bios = nouveau_bios(gpio); 30 struct nouveau_bios *bios = nouveau_bios(gpio);
35 struct nvd0_gpio_priv *priv = (void *)gpio;
36 u8 ver, len; 31 u8 ver, len;
37 u16 entry; 32 u16 entry;
38 int ent = -1; 33 int ent = -1;
@@ -51,9 +46,9 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match)
51 46
52 gpio->set(gpio, 0, func, line, defs); 47 gpio->set(gpio, 0, func, line, defs);
53 48
54 nv_mask(priv, 0x00d610 + (line * 4), 0xff, unk0); 49 nv_mask(gpio, 0x00d610 + (line * 4), 0xff, unk0);
55 if (unk1--) 50 if (unk1--)
56 nv_mask(priv, 0x00d740 + (unk1 * 4), 0xff, line); 51 nv_mask(gpio, 0x00d740 + (unk1 * 4), 0xff, line);
57 } 52 }
58} 53}
59 54
@@ -72,36 +67,19 @@ nvd0_gpio_sense(struct nouveau_gpio *gpio, int line)
72 return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000); 67 return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000);
73} 68}
74 69
75static int 70struct nouveau_oclass *
76nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 71nvd0_gpio_oclass = &(struct nouveau_gpio_impl) {
77 struct nouveau_oclass *oclass, void *data, u32 size, 72 .base.handle = NV_SUBDEV(GPIO, 0xd0),
78 struct nouveau_object **pobject) 73 .base.ofuncs = &(struct nouveau_ofuncs) {
79{ 74 .ctor = _nouveau_gpio_ctor,
80 struct nvd0_gpio_priv *priv; 75 .dtor = _nouveau_gpio_dtor,
81 int ret; 76 .init = _nouveau_gpio_init,
82 77 .fini = _nouveau_gpio_fini,
83 ret = nouveau_gpio_create(parent, engine, oclass, 32, &priv);
84 *pobject = nv_object(priv);
85 if (ret)
86 return ret;
87
88 priv->base.reset = nvd0_gpio_reset;
89 priv->base.drive = nvd0_gpio_drive;
90 priv->base.sense = nvd0_gpio_sense;
91 priv->base.events->priv = priv;
92 priv->base.events->enable = nv50_gpio_intr_enable;
93 priv->base.events->disable = nv50_gpio_intr_disable;
94 nv_subdev(priv)->intr = nv50_gpio_intr;
95 return 0;
96}
97
98struct nouveau_oclass
99nvd0_gpio_oclass = {
100 .handle = NV_SUBDEV(GPIO, 0xd0),
101 .ofuncs = &(struct nouveau_ofuncs) {
102 .ctor = nvd0_gpio_ctor,
103 .dtor = nv50_gpio_dtor,
104 .init = nv50_gpio_init,
105 .fini = nv50_gpio_fini,
106 }, 78 },
107}; 79 .lines = 32,
80 .intr_stat = nv92_gpio_intr_stat,
81 .intr_mask = nv92_gpio_intr_mask,
82 .drive = nvd0_gpio_drive,
83 .sense = nvd0_gpio_sense,
84 .reset = nvd0_gpio_reset,
85}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c
index 8988621373b0..e1145b48c76c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c
@@ -24,108 +24,51 @@
24 24
25#include "priv.h" 25#include "priv.h"
26 26
27struct nve0_gpio_priv { 27static void
28 struct nouveau_gpio base; 28nve0_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
29};
30
31void
32nve0_gpio_intr(struct nouveau_subdev *subdev)
33{ 29{
34 struct nve0_gpio_priv *priv = (void *)subdev; 30 u32 intr0 = nv_rd32(gpio, 0x00dc00);
35 u32 intr0 = nv_rd32(priv, 0xdc00) & nv_rd32(priv, 0xdc08); 31 u32 intr1 = nv_rd32(gpio, 0x00dc80);
36 u32 intr1 = nv_rd32(priv, 0xdc80) & nv_rd32(priv, 0xdc88); 32 u32 stat0 = nv_rd32(gpio, 0x00dc08) & intr0;
37 u32 hi = (intr0 & 0x0000ffff) | (intr1 << 16); 33 u32 stat1 = nv_rd32(gpio, 0x00dc88) & intr1;
38 u32 lo = (intr0 >> 16) | (intr1 & 0xffff0000); 34 *lo = (stat1 & 0xffff0000) | (stat0 >> 16);
39 int i; 35 *hi = (stat1 << 16) | (stat0 & 0x0000ffff);
40 36 nv_wr32(gpio, 0x00dc00, intr0);
41 for (i = 0; (hi | lo) && i < 32; i++) { 37 nv_wr32(gpio, 0x00dc80, intr1);
42 if ((hi | lo) & (1 << i))
43 nouveau_event_trigger(priv->base.events, i);
44 }
45
46 nv_wr32(priv, 0xdc00, intr0);
47 nv_wr32(priv, 0xdc80, intr1);
48} 38}
49 39
50void 40void
51nve0_gpio_intr_enable(struct nouveau_event *event, int line) 41nve0_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
52{ 42{
53 const u32 addr = line < 16 ? 0xdc00 : 0xdc80; 43 u32 inte0 = nv_rd32(gpio, 0x00dc08);
54 const u32 mask = 0x00010001 << (line & 0xf); 44 u32 inte1 = nv_rd32(gpio, 0x00dc88);
55 nv_wr32(event->priv, addr + 0x00, mask); 45 if (type & NVKM_GPIO_LO)
56 nv_mask(event->priv, addr + 0x08, mask, mask); 46 inte0 = (inte0 & ~(mask << 16)) | (data << 16);
57} 47 if (type & NVKM_GPIO_HI)
58 48 inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
59void 49 mask >>= 16;
60nve0_gpio_intr_disable(struct nouveau_event *event, int line) 50 data >>= 16;
61{ 51 if (type & NVKM_GPIO_LO)
62 const u32 addr = line < 16 ? 0xdc00 : 0xdc80; 52 inte1 = (inte1 & ~(mask << 16)) | (data << 16);
63 const u32 mask = 0x00010001 << (line & 0xf); 53 if (type & NVKM_GPIO_HI)
64 nv_mask(event->priv, addr + 0x08, mask, 0x00000000); 54 inte1 = (inte1 & ~mask) | data;
65 nv_wr32(event->priv, addr + 0x00, mask); 55 nv_wr32(gpio, 0x00dc08, inte0);
66} 56 nv_wr32(gpio, 0x00dc88, inte1);
67
68int
69nve0_gpio_fini(struct nouveau_object *object, bool suspend)
70{
71 struct nve0_gpio_priv *priv = (void *)object;
72 nv_wr32(priv, 0xdc08, 0x00000000);
73 nv_wr32(priv, 0xdc88, 0x00000000);
74 return nouveau_gpio_fini(&priv->base, suspend);
75}
76
77int
78nve0_gpio_init(struct nouveau_object *object)
79{
80 struct nve0_gpio_priv *priv = (void *)object;
81 int ret;
82
83 ret = nouveau_gpio_init(&priv->base);
84 if (ret)
85 return ret;
86
87 nv_wr32(priv, 0xdc00, 0xffffffff);
88 nv_wr32(priv, 0xdc80, 0xffffffff);
89 return 0;
90}
91
92void
93nve0_gpio_dtor(struct nouveau_object *object)
94{
95 struct nve0_gpio_priv *priv = (void *)object;
96 nouveau_gpio_destroy(&priv->base);
97}
98
99static int
100nve0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
101 struct nouveau_oclass *oclass, void *data, u32 size,
102 struct nouveau_object **pobject)
103{
104 struct nve0_gpio_priv *priv;
105 int ret;
106
107 ret = nouveau_gpio_create(parent, engine, oclass, 32, &priv);
108 *pobject = nv_object(priv);
109 if (ret)
110 return ret;
111
112 priv->base.reset = nvd0_gpio_reset;
113 priv->base.drive = nvd0_gpio_drive;
114 priv->base.sense = nvd0_gpio_sense;
115 priv->base.events->priv = priv;
116 priv->base.events->enable = nve0_gpio_intr_enable;
117 priv->base.events->disable = nve0_gpio_intr_disable;
118 nv_subdev(priv)->intr = nve0_gpio_intr;
119 return 0;
120} 57}
121 58
122struct nouveau_oclass 59struct nouveau_oclass *
123nve0_gpio_oclass = { 60nve0_gpio_oclass = &(struct nouveau_gpio_impl) {
124 .handle = NV_SUBDEV(GPIO, 0xe0), 61 .base.handle = NV_SUBDEV(GPIO, 0xe0),
125 .ofuncs = &(struct nouveau_ofuncs) { 62 .base.ofuncs = &(struct nouveau_ofuncs) {
126 .ctor = nve0_gpio_ctor, 63 .ctor = _nouveau_gpio_ctor,
127 .dtor = nv50_gpio_dtor, 64 .dtor = _nouveau_gpio_dtor,
128 .init = nve0_gpio_init, 65 .init = _nouveau_gpio_init,
129 .fini = nve0_gpio_fini, 66 .fini = _nouveau_gpio_fini,
130 }, 67 },
131}; 68 .lines = 32,
69 .intr_stat = nve0_gpio_intr_stat,
70 .intr_mask = nve0_gpio_intr_mask,
71 .drive = nvd0_gpio_drive,
72 .sense = nvd0_gpio_sense,
73 .reset = nvd0_gpio_reset,
74}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h
index 2ee1c895c782..e1724dfc86ae 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h
@@ -3,15 +3,65 @@
3 3
4#include <subdev/gpio.h> 4#include <subdev/gpio.h>
5 5
6void nv50_gpio_dtor(struct nouveau_object *); 6#define nouveau_gpio_create(p,e,o,d) \
7int nv50_gpio_init(struct nouveau_object *); 7 nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d)
8int nv50_gpio_fini(struct nouveau_object *, bool); 8#define nouveau_gpio_destroy(p) ({ \
9void nv50_gpio_intr(struct nouveau_subdev *); 9 struct nouveau_gpio *gpio = (p); \
10void nv50_gpio_intr_enable(struct nouveau_event *, int line); 10 _nouveau_gpio_dtor(nv_object(gpio)); \
11void nv50_gpio_intr_disable(struct nouveau_event *, int line); 11})
12#define nouveau_gpio_init(p) ({ \
13 struct nouveau_gpio *gpio = (p); \
14 _nouveau_gpio_init(nv_object(gpio)); \
15})
16#define nouveau_gpio_fini(p,s) ({ \
17 struct nouveau_gpio *gpio = (p); \
18 _nouveau_gpio_fini(nv_object(gpio), (s)); \
19})
20
21int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
22 struct nouveau_oclass *, int, void **);
23int _nouveau_gpio_ctor(struct nouveau_object *, struct nouveau_object *,
24 struct nouveau_oclass *, void *, u32,
25 struct nouveau_object **);
26void _nouveau_gpio_dtor(struct nouveau_object *);
27int _nouveau_gpio_init(struct nouveau_object *);
28int _nouveau_gpio_fini(struct nouveau_object *, bool);
29
30struct nouveau_gpio_impl {
31 struct nouveau_oclass base;
32 int lines;
33
34 /* read and ack pending interrupts, returning only data
35 * for lines that have not been masked off, while still
36 * performing the ack for anything that was pending.
37 */
38 void (*intr_stat)(struct nouveau_gpio *, u32 *, u32 *);
39
40 /* mask on/off interrupts for hi/lo transitions on a
41 * given set of gpio lines
42 */
43 void (*intr_mask)(struct nouveau_gpio *, u32, u32, u32);
44
45 /* configure gpio direction and output value */
46 int (*drive)(struct nouveau_gpio *, int line, int dir, int out);
47
48 /* sense current state of given gpio line */
49 int (*sense)(struct nouveau_gpio *, int line);
50
51 /*XXX*/
52 void (*reset)(struct nouveau_gpio *, u8);
53};
54
55void nv50_gpio_reset(struct nouveau_gpio *, u8);
56int nv50_gpio_drive(struct nouveau_gpio *, int, int, int);
57int nv50_gpio_sense(struct nouveau_gpio *, int);
58
59void nv92_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *);
60void nv92_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32);
12 61
13void nvd0_gpio_reset(struct nouveau_gpio *, u8); 62void nvd0_gpio_reset(struct nouveau_gpio *, u8);
14int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int); 63int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int);
15int nvd0_gpio_sense(struct nouveau_gpio *, int); 64int nvd0_gpio_sense(struct nouveau_gpio *, int);
16 65
66
17#endif 67#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
index 4b195ac4da66..2c2731a6cf91 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
@@ -22,7 +22,7 @@
22 * Authors: Ben Skeggs <bskeggs@redhat.com> 22 * Authors: Ben Skeggs <bskeggs@redhat.com>
23 */ 23 */
24 24
25#include <subdev/i2c.h> 25#include "port.h"
26 26
27struct anx9805_i2c_port { 27struct anx9805_i2c_port {
28 struct nouveau_i2c_port base; 28 struct nouveau_i2c_port base;
@@ -37,6 +37,8 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh)
37 struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; 37 struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
38 u8 tmp, i; 38 u8 tmp, i;
39 39
40 DBG("ANX9805 train %d 0x%02x %d\n", link_nr, link_bw, enh);
41
40 nv_wri2cr(mast, chan->addr, 0xa0, link_bw); 42 nv_wri2cr(mast, chan->addr, 0xa0, link_bw);
41 nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); 43 nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00));
42 nv_wri2cr(mast, chan->addr, 0xa2, 0x01); 44 nv_wri2cr(mast, chan->addr, 0xa2, 0x01);
@@ -60,21 +62,29 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh)
60} 62}
61 63
62static int 64static int
63anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size) 65anx9805_aux(struct nouveau_i2c_port *port, bool retry,
66 u8 type, u32 addr, u8 *data, u8 size)
64{ 67{
65 struct anx9805_i2c_port *chan = (void *)port; 68 struct anx9805_i2c_port *chan = (void *)port;
66 struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; 69 struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
67 int i, ret = -ETIMEDOUT; 70 int i, ret = -ETIMEDOUT;
71 u8 buf[16] = {};
68 u8 tmp; 72 u8 tmp;
69 73
74 DBG("%02x %05x %d\n", type, addr, size);
75
70 tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04; 76 tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04;
71 nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04); 77 nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04);
72 nv_wri2cr(mast, chan->ctrl, 0x07, tmp); 78 nv_wri2cr(mast, chan->ctrl, 0x07, tmp);
73 nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); 79 nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
74 80
75 nv_wri2cr(mast, chan->addr, 0xe4, 0x80); 81 nv_wri2cr(mast, chan->addr, 0xe4, 0x80);
76 for (i = 0; !(type & 1) && i < size; i++) 82 if (!(type & 1)) {
77 nv_wri2cr(mast, chan->addr, 0xf0 + i, data[i]); 83 memcpy(buf, data, size);
84 DBG("%16ph", buf);
85 for (i = 0; i < size; i++)
86 nv_wri2cr(mast, chan->addr, 0xf0 + i, buf[i]);
87 }
78 nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type); 88 nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type);
79 nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0); 89 nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0);
80 nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8); 90 nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8);
@@ -93,8 +103,13 @@ anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size)
93 goto done; 103 goto done;
94 } 104 }
95 105
96 for (i = 0; (type & 1) && i < size; i++) 106 if (type & 1) {
97 data[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i); 107 for (i = 0; i < size; i++)
108 buf[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i);
109 DBG("%16ph", buf);
110 memcpy(data, buf, size);
111 }
112
98 ret = 0; 113 ret = 0;
99done: 114done:
100 nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); 115 nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
index 5de074ad170b..02eb42be2e9e 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
@@ -22,15 +22,19 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24 24
25#include <subdev/i2c.h> 25#include "priv.h"
26 26
27int 27int
28nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) 28nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
29{ 29{
30 struct nouveau_i2c *i2c = nouveau_i2c(port);
30 if (port->func->aux) { 31 if (port->func->aux) {
31 if (port->func->acquire) 32 int ret = i2c->acquire(port, 0);
32 port->func->acquire(port); 33 if (ret == 0) {
33 return port->func->aux(port, 9, addr, data, size); 34 ret = port->func->aux(port, true, 9, addr, data, size);
35 i2c->release(port);
36 }
37 return ret;
34 } 38 }
35 return -ENODEV; 39 return -ENODEV;
36} 40}
@@ -38,10 +42,14 @@ nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
38int 42int
39nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) 43nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
40{ 44{
45 struct nouveau_i2c *i2c = nouveau_i2c(port);
41 if (port->func->aux) { 46 if (port->func->aux) {
42 if (port->func->acquire) 47 int ret = i2c->acquire(port, 0);
43 port->func->acquire(port); 48 if (ret == 0) {
44 return port->func->aux(port, 8, addr, data, size); 49 ret = port->func->aux(port, true, 8, addr, data, size);
50 i2c->release(port);
51 }
52 return ret;
45 } 53 }
46 return -ENODEV; 54 return -ENODEV;
47} 55}
@@ -50,13 +58,16 @@ static int
50aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 58aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
51{ 59{
52 struct nouveau_i2c_port *port = adap->algo_data; 60 struct nouveau_i2c_port *port = adap->algo_data;
61 struct nouveau_i2c *i2c = nouveau_i2c(port);
53 struct i2c_msg *msg = msgs; 62 struct i2c_msg *msg = msgs;
54 int ret, mcnt = num; 63 int ret, mcnt = num;
55 64
56 if (!port->func->aux) 65 if (!port->func->aux)
57 return -ENODEV; 66 return -ENODEV;
58 if ( port->func->acquire) 67
59 port->func->acquire(port); 68 ret = i2c->acquire(port, 0);
69 if (ret)
70 return ret;
60 71
61 while (mcnt--) { 72 while (mcnt--) {
62 u8 remaining = msg->len; 73 u8 remaining = msg->len;
@@ -74,9 +85,11 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
74 if (mcnt || remaining > 16) 85 if (mcnt || remaining > 16)
75 cmd |= 4; /* MOT */ 86 cmd |= 4; /* MOT */
76 87
77 ret = port->func->aux(port, cmd, msg->addr, ptr, cnt); 88 ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
78 if (ret < 0) 89 if (ret < 0) {
90 i2c->release(port);
79 return ret; 91 return ret;
92 }
80 93
81 ptr += cnt; 94 ptr += cnt;
82 remaining -= cnt; 95 remaining -= cnt;
@@ -85,6 +98,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
85 msg++; 98 msg++;
86 } 99 }
87 100
101 i2c->release(port);
88 return num; 102 return num;
89} 103}
90 104
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
index 378e05b88e6f..09ba2cc851cf 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
@@ -23,13 +23,16 @@
23 */ 23 */
24 24
25#include <core/option.h> 25#include <core/option.h>
26#include <core/event.h>
26 27
27#include <subdev/bios.h> 28#include <subdev/bios.h>
28#include <subdev/bios/dcb.h> 29#include <subdev/bios/dcb.h>
29#include <subdev/bios/i2c.h> 30#include <subdev/bios/i2c.h>
30#include <subdev/i2c.h>
31#include <subdev/vga.h> 31#include <subdev/vga.h>
32 32
33#include "priv.h"
34#include "pad.h"
35
33/****************************************************************************** 36/******************************************************************************
34 * interface to linux i2c bit-banging algorithm 37 * interface to linux i2c bit-banging algorithm
35 *****************************************************************************/ 38 *****************************************************************************/
@@ -45,9 +48,15 @@ nouveau_i2c_pre_xfer(struct i2c_adapter *adap)
45{ 48{
46 struct i2c_algo_bit_data *bit = adap->algo_data; 49 struct i2c_algo_bit_data *bit = adap->algo_data;
47 struct nouveau_i2c_port *port = bit->data; 50 struct nouveau_i2c_port *port = bit->data;
48 if (port->func->acquire) 51 return nouveau_i2c(port)->acquire(port, bit->timeout);
49 port->func->acquire(port); 52}
50 return 0; 53
54static void
55nouveau_i2c_post_xfer(struct i2c_adapter *adap)
56{
57 struct i2c_algo_bit_data *bit = adap->algo_data;
58 struct nouveau_i2c_port *port = bit->data;
59 return nouveau_i2c(port)->release(port);
51} 60}
52 61
53static void 62static void
@@ -82,6 +91,15 @@ nouveau_i2c_getsda(void *data)
82 * base i2c "port" class implementation 91 * base i2c "port" class implementation
83 *****************************************************************************/ 92 *****************************************************************************/
84 93
94int
95_nouveau_i2c_port_fini(struct nouveau_object *object, bool suspend)
96{
97 struct nouveau_i2c_port *port = (void *)object;
98 struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
99 nv_ofuncs(pad)->fini(nv_object(pad), suspend);
100 return nouveau_object_fini(&port->base, suspend);
101}
102
85void 103void
86_nouveau_i2c_port_dtor(struct nouveau_object *object) 104_nouveau_i2c_port_dtor(struct nouveau_object *object)
87{ 105{
@@ -98,7 +116,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
98 const struct nouveau_i2c_func *func, 116 const struct nouveau_i2c_func *func,
99 int size, void **pobject) 117 int size, void **pobject)
100{ 118{
101 struct nouveau_device *device = nv_device(parent); 119 struct nouveau_device *device = nv_device(engine);
102 struct nouveau_i2c *i2c = (void *)engine; 120 struct nouveau_i2c *i2c = (void *)engine;
103 struct nouveau_i2c_port *port; 121 struct nouveau_i2c_port *port;
104 int ret; 122 int ret;
@@ -113,8 +131,9 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
113 port->adapter.owner = THIS_MODULE; 131 port->adapter.owner = THIS_MODULE;
114 port->adapter.dev.parent = nv_device_base(device); 132 port->adapter.dev.parent = nv_device_base(device);
115 port->index = index; 133 port->index = index;
134 port->aux = -1;
116 port->func = func; 135 port->func = func;
117 i2c_set_adapdata(&port->adapter, i2c); 136 mutex_init(&port->mutex);
118 137
119 if ( algo == &nouveau_i2c_bit_algo && 138 if ( algo == &nouveau_i2c_bit_algo &&
120 !nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) { 139 !nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) {
@@ -128,6 +147,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
128 bit->timeout = usecs_to_jiffies(2200); 147 bit->timeout = usecs_to_jiffies(2200);
129 bit->data = port; 148 bit->data = port;
130 bit->pre_xfer = nouveau_i2c_pre_xfer; 149 bit->pre_xfer = nouveau_i2c_pre_xfer;
150 bit->post_xfer = nouveau_i2c_post_xfer;
131 bit->setsda = nouveau_i2c_setsda; 151 bit->setsda = nouveau_i2c_setsda;
132 bit->setscl = nouveau_i2c_setscl; 152 bit->setscl = nouveau_i2c_setscl;
133 bit->getsda = nouveau_i2c_getsda; 153 bit->getsda = nouveau_i2c_getsda;
@@ -141,7 +161,6 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
141 ret = i2c_add_adapter(&port->adapter); 161 ret = i2c_add_adapter(&port->adapter);
142 } 162 }
143 163
144 /* drop port's i2c subdev refcount, i2c handles this itself */
145 if (ret == 0) 164 if (ret == 0)
146 list_add_tail(&port->head, &i2c->ports); 165 list_add_tail(&port->head, &i2c->ports);
147 return ret; 166 return ret;
@@ -193,6 +212,75 @@ nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
193 return NULL; 212 return NULL;
194} 213}
195 214
215static void
216nouveau_i2c_release_pad(struct nouveau_i2c_port *port)
217{
218 struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
219 struct nouveau_i2c *i2c = nouveau_i2c(port);
220
221 if (atomic_dec_and_test(&nv_object(pad)->usecount)) {
222 nv_ofuncs(pad)->fini(nv_object(pad), false);
223 wake_up_all(&i2c->wait);
224 }
225}
226
227static int
228nouveau_i2c_try_acquire_pad(struct nouveau_i2c_port *port)
229{
230 struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
231
232 if (atomic_add_return(1, &nv_object(pad)->usecount) != 1) {
233 struct nouveau_object *owner = (void *)pad->port;
234 do {
235 if (owner == (void *)port)
236 return 0;
237 owner = owner->parent;
238 } while(owner);
239 nouveau_i2c_release_pad(port);
240 return -EBUSY;
241 }
242
243 pad->next = port;
244 nv_ofuncs(pad)->init(nv_object(pad));
245 return 0;
246}
247
248static int
249nouveau_i2c_acquire_pad(struct nouveau_i2c_port *port, unsigned long timeout)
250{
251 struct nouveau_i2c *i2c = nouveau_i2c(port);
252
253 if (timeout) {
254 if (wait_event_timeout(i2c->wait,
255 nouveau_i2c_try_acquire_pad(port) == 0,
256 timeout) == 0)
257 return -EBUSY;
258 } else {
259 wait_event(i2c->wait, nouveau_i2c_try_acquire_pad(port) == 0);
260 }
261
262 return 0;
263}
264
265static void
266nouveau_i2c_release(struct nouveau_i2c_port *port)
267__releases(pad->mutex)
268{
269 nouveau_i2c(port)->release_pad(port);
270 mutex_unlock(&port->mutex);
271}
272
273static int
274nouveau_i2c_acquire(struct nouveau_i2c_port *port, unsigned long timeout)
275__acquires(pad->mutex)
276{
277 int ret;
278 mutex_lock(&port->mutex);
279 if ((ret = nouveau_i2c(port)->acquire_pad(port, timeout)))
280 mutex_unlock(&port->mutex);
281 return ret;
282}
283
196static int 284static int
197nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, 285nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
198 struct nouveau_i2c_board_info *info, 286 struct nouveau_i2c_board_info *info,
@@ -237,11 +325,59 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
237 return -ENODEV; 325 return -ENODEV;
238} 326}
239 327
328static void
329nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index)
330{
331 struct nouveau_i2c *i2c = nouveau_i2c(event->priv);
332 struct nouveau_i2c_port *port = i2c->find(i2c, index);
333 const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
334 if (port && port->aux >= 0)
335 impl->aux_mask(i2c, type, 1 << port->aux, 0);
336}
337
338static void
339nouveau_i2c_intr_enable(struct nouveau_event *event, int type, int index)
340{
341 struct nouveau_i2c *i2c = nouveau_i2c(event->priv);
342 struct nouveau_i2c_port *port = i2c->find(i2c, index);
343 const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
344 if (port && port->aux >= 0)
345 impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux);
346}
347
348static void
349nouveau_i2c_intr(struct nouveau_subdev *subdev)
350{
351 struct nouveau_i2c_impl *impl = (void *)nv_oclass(subdev);
352 struct nouveau_i2c *i2c = nouveau_i2c(subdev);
353 struct nouveau_i2c_port *port;
354 u32 hi, lo, rq, tx, e;
355
356 if (impl->aux_stat) {
357 impl->aux_stat(i2c, &hi, &lo, &rq, &tx);
358 if (hi || lo || rq || tx) {
359 list_for_each_entry(port, &i2c->ports, head) {
360 if (e = 0, port->aux < 0)
361 continue;
362
363 if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG;
364 if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG;
365 if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ;
366 if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE;
367
368 nouveau_event_trigger(i2c->ntfy, e, port->index);
369 }
370 }
371 }
372}
373
240int 374int
241_nouveau_i2c_fini(struct nouveau_object *object, bool suspend) 375_nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
242{ 376{
377 struct nouveau_i2c_impl *impl = (void *)nv_oclass(object);
243 struct nouveau_i2c *i2c = (void *)object; 378 struct nouveau_i2c *i2c = (void *)object;
244 struct nouveau_i2c_port *port; 379 struct nouveau_i2c_port *port;
380 u32 mask;
245 int ret; 381 int ret;
246 382
247 list_for_each_entry(port, &i2c->ports, head) { 383 list_for_each_entry(port, &i2c->ports, head) {
@@ -250,6 +386,11 @@ _nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
250 goto fail; 386 goto fail;
251 } 387 }
252 388
389 if ((mask = (1 << impl->aux) - 1), impl->aux_stat) {
390 impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
391 impl->aux_stat(i2c, &mask, &mask, &mask, &mask);
392 }
393
253 return nouveau_subdev_fini(&i2c->base, suspend); 394 return nouveau_subdev_fini(&i2c->base, suspend);
254fail: 395fail:
255 list_for_each_entry_continue_reverse(port, &i2c->ports, head) { 396 list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
@@ -290,6 +431,8 @@ _nouveau_i2c_dtor(struct nouveau_object *object)
290 struct nouveau_i2c *i2c = (void *)object; 431 struct nouveau_i2c *i2c = (void *)object;
291 struct nouveau_i2c_port *port, *temp; 432 struct nouveau_i2c_port *port, *temp;
292 433
434 nouveau_event_destroy(&i2c->ntfy);
435
293 list_for_each_entry_safe(port, temp, &i2c->ports, head) { 436 list_for_each_entry_safe(port, temp, &i2c->ports, head) {
294 nouveau_object_ref(NULL, (struct nouveau_object **)&port); 437 nouveau_object_ref(NULL, (struct nouveau_object **)&port);
295 } 438 }
@@ -306,14 +449,14 @@ int
306nouveau_i2c_create_(struct nouveau_object *parent, 449nouveau_i2c_create_(struct nouveau_object *parent,
307 struct nouveau_object *engine, 450 struct nouveau_object *engine,
308 struct nouveau_oclass *oclass, 451 struct nouveau_oclass *oclass,
309 struct nouveau_oclass *sclass,
310 int length, void **pobject) 452 int length, void **pobject)
311{ 453{
454 const struct nouveau_i2c_impl *impl = (void *)oclass;
312 struct nouveau_bios *bios = nouveau_bios(parent); 455 struct nouveau_bios *bios = nouveau_bios(parent);
313 struct nouveau_i2c *i2c; 456 struct nouveau_i2c *i2c;
314 struct nouveau_object *object; 457 struct nouveau_object *object;
315 struct dcb_i2c_entry info; 458 struct dcb_i2c_entry info;
316 int ret, i, j, index = -1; 459 int ret, i, j, index = -1, pad;
317 struct dcb_output outp; 460 struct dcb_output outp;
318 u8 ver, hdr; 461 u8 ver, hdr;
319 u32 data; 462 u32 data;
@@ -324,24 +467,48 @@ nouveau_i2c_create_(struct nouveau_object *parent,
324 if (ret) 467 if (ret)
325 return ret; 468 return ret;
326 469
470 nv_subdev(i2c)->intr = nouveau_i2c_intr;
327 i2c->find = nouveau_i2c_find; 471 i2c->find = nouveau_i2c_find;
328 i2c->find_type = nouveau_i2c_find_type; 472 i2c->find_type = nouveau_i2c_find_type;
473 i2c->acquire_pad = nouveau_i2c_acquire_pad;
474 i2c->release_pad = nouveau_i2c_release_pad;
475 i2c->acquire = nouveau_i2c_acquire;
476 i2c->release = nouveau_i2c_release;
329 i2c->identify = nouveau_i2c_identify; 477 i2c->identify = nouveau_i2c_identify;
478 init_waitqueue_head(&i2c->wait);
330 INIT_LIST_HEAD(&i2c->ports); 479 INIT_LIST_HEAD(&i2c->ports);
331 480
332 while (!dcb_i2c_parse(bios, ++index, &info)) { 481 while (!dcb_i2c_parse(bios, ++index, &info)) {
333 if (info.type == DCB_I2C_UNUSED) 482 if (info.type == DCB_I2C_UNUSED)
334 continue; 483 continue;
335 484
336 oclass = sclass; 485 if (info.share != DCB_I2C_UNUSED) {
486 if (info.type == DCB_I2C_NVIO_AUX)
487 pad = info.drive;
488 else
489 pad = info.share;
490 oclass = impl->pad_s;
491 } else {
492 pad = 0x100 + info.drive;
493 oclass = impl->pad_x;
494 }
495
496 ret = nouveau_object_ctor(NULL, *pobject, oclass,
497 NULL, pad, &parent);
498 if (ret < 0)
499 continue;
500
501 oclass = impl->sclass;
337 do { 502 do {
338 ret = -EINVAL; 503 ret = -EINVAL;
339 if (oclass->handle == info.type) { 504 if (oclass->handle == info.type) {
340 ret = nouveau_object_ctor(*pobject, *pobject, 505 ret = nouveau_object_ctor(parent, *pobject,
341 oclass, &info, 506 oclass, &info,
342 index, &object); 507 index, &object);
343 } 508 }
344 } while (ret && (++oclass)->handle); 509 } while (ret && (++oclass)->handle);
510
511 nouveau_object_ref(NULL, &parent);
345 } 512 }
346 513
347 /* in addition to the busses specified in the i2c table, there 514 /* in addition to the busses specified in the i2c table, there
@@ -380,5 +547,28 @@ nouveau_i2c_create_(struct nouveau_object *parent,
380 } 547 }
381 } 548 }
382 549
550 ret = nouveau_event_create(4, index, &i2c->ntfy);
551 if (ret)
552 return ret;
553
554 i2c->ntfy->priv = i2c;
555 i2c->ntfy->enable = nouveau_i2c_intr_enable;
556 i2c->ntfy->disable = nouveau_i2c_intr_disable;
557 return 0;
558}
559
560int
561_nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
562 struct nouveau_oclass *oclass, void *data, u32 size,
563 struct nouveau_object **pobject)
564{
565 struct nouveau_i2c *i2c;
566 int ret;
567
568 ret = nouveau_i2c_create(parent, engine, oclass, &i2c);
569 *pobject = nv_object(i2c);
570 if (ret)
571 return ret;
572
383 return 0; 573 return 0;
384} 574}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c
index a6e72d3b06b5..813ffc96e864 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c
@@ -22,7 +22,7 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24 24
25#include "subdev/i2c.h" 25#include "priv.h"
26 26
27#ifdef CONFIG_NOUVEAU_I2C_INTERNAL 27#ifdef CONFIG_NOUVEAU_I2C_INTERNAL
28#define T_TIMEOUT 2200000 28#define T_TIMEOUT 2200000
@@ -187,8 +187,9 @@ i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
187 struct i2c_msg *msg = msgs; 187 struct i2c_msg *msg = msgs;
188 int ret = 0, mcnt = num; 188 int ret = 0, mcnt = num;
189 189
190 if (port->func->acquire) 190 ret = nouveau_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT));
191 port->func->acquire(port); 191 if (ret)
192 return ret;
192 193
193 while (!ret && mcnt--) { 194 while (!ret && mcnt--) {
194 u8 remaining = msg->len; 195 u8 remaining = msg->len;
@@ -210,6 +211,7 @@ i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
210 } 211 }
211 212
212 i2c_stop(port); 213 i2c_stop(port);
214 nouveau_i2c(port)->release(port);
213 return (ret < 0) ? ret : num; 215 return (ret < 0) ? ret : num;
214} 216}
215#else 217#else
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c
index 860d5d2365da..b1725bdea967 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c
@@ -22,9 +22,10 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24 24
25#include <subdev/i2c.h>
26#include <subdev/vga.h> 25#include <subdev/vga.h>
27 26
27#include "priv.h"
28
28struct nv04_i2c_priv { 29struct nv04_i2c_priv {
29 struct nouveau_i2c base; 30 struct nouveau_i2c base;
30}; 31};
@@ -115,29 +116,15 @@ nv04_i2c_sclass[] = {
115 {} 116 {}
116}; 117};
117 118
118static int 119struct nouveau_oclass *
119nv04_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 120nv04_i2c_oclass = &(struct nouveau_i2c_impl) {
120 struct nouveau_oclass *oclass, void *data, u32 size, 121 .base.handle = NV_SUBDEV(I2C, 0x04),
121 struct nouveau_object **pobject) 122 .base.ofuncs = &(struct nouveau_ofuncs) {
122{ 123 .ctor = _nouveau_i2c_ctor,
123 struct nv04_i2c_priv *priv;
124 int ret;
125
126 ret = nouveau_i2c_create(parent, engine, oclass, nv04_i2c_sclass, &priv);
127 *pobject = nv_object(priv);
128 if (ret)
129 return ret;
130
131 return 0;
132}
133
134struct nouveau_oclass
135nv04_i2c_oclass = {
136 .handle = NV_SUBDEV(I2C, 0x04),
137 .ofuncs = &(struct nouveau_ofuncs) {
138 .ctor = nv04_i2c_ctor,
139 .dtor = _nouveau_i2c_dtor, 124 .dtor = _nouveau_i2c_dtor,
140 .init = _nouveau_i2c_init, 125 .init = _nouveau_i2c_init,
141 .fini = _nouveau_i2c_fini, 126 .fini = _nouveau_i2c_fini,
142 }, 127 },
143}; 128 .sclass = nv04_i2c_sclass,
129 .pad_x = &nv04_i2c_pad_oclass,
130}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c
index 0c2655a03bb4..f16c87ce5ba1 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c
@@ -22,9 +22,10 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24 24
25#include <subdev/i2c.h>
26#include <subdev/vga.h> 25#include <subdev/vga.h>
27 26
27#include "priv.h"
28
28struct nv4e_i2c_priv { 29struct nv4e_i2c_priv {
29 struct nouveau_i2c base; 30 struct nouveau_i2c base;
30}; 31};
@@ -107,29 +108,15 @@ nv4e_i2c_sclass[] = {
107 {} 108 {}
108}; 109};
109 110
110static int 111struct nouveau_oclass *
111nv4e_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 112nv4e_i2c_oclass = &(struct nouveau_i2c_impl) {
112 struct nouveau_oclass *oclass, void *data, u32 size, 113 .base.handle = NV_SUBDEV(I2C, 0x4e),
113 struct nouveau_object **pobject) 114 .base.ofuncs = &(struct nouveau_ofuncs) {
114{ 115 .ctor = _nouveau_i2c_ctor,
115 struct nv4e_i2c_priv *priv;
116 int ret;
117
118 ret = nouveau_i2c_create(parent, engine, oclass, nv4e_i2c_sclass, &priv);
119 *pobject = nv_object(priv);
120 if (ret)
121 return ret;
122
123 return 0;
124}
125
126struct nouveau_oclass
127nv4e_i2c_oclass = {
128 .handle = NV_SUBDEV(I2C, 0x4e),
129 .ofuncs = &(struct nouveau_ofuncs) {
130 .ctor = nv4e_i2c_ctor,
131 .dtor = _nouveau_i2c_dtor, 116 .dtor = _nouveau_i2c_dtor,
132 .init = _nouveau_i2c_init, 117 .init = _nouveau_i2c_init,
133 .fini = _nouveau_i2c_fini, 118 .fini = _nouveau_i2c_fini,
134 }, 119 },
135}; 120 .sclass = nv4e_i2c_sclass,
121 .pad_x = &nv04_i2c_pad_oclass,
122}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c
index a8d67a287704..7b8756d4df08 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c
@@ -121,29 +121,15 @@ nv50_i2c_sclass[] = {
121 {} 121 {}
122}; 122};
123 123
124static int 124struct nouveau_oclass *
125nv50_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 125nv50_i2c_oclass = &(struct nouveau_i2c_impl) {
126 struct nouveau_oclass *oclass, void *data, u32 size, 126 .base.handle = NV_SUBDEV(I2C, 0x50),
127 struct nouveau_object **pobject) 127 .base.ofuncs = &(struct nouveau_ofuncs) {
128{ 128 .ctor = _nouveau_i2c_ctor,
129 struct nv50_i2c_priv *priv;
130 int ret;
131
132 ret = nouveau_i2c_create(parent, engine, oclass, nv50_i2c_sclass, &priv);
133 *pobject = nv_object(priv);
134 if (ret)
135 return ret;
136
137 return 0;
138}
139
140struct nouveau_oclass
141nv50_i2c_oclass = {
142 .handle = NV_SUBDEV(I2C, 0x50),
143 .ofuncs = &(struct nouveau_ofuncs) {
144 .ctor = nv50_i2c_ctor,
145 .dtor = _nouveau_i2c_dtor, 129 .dtor = _nouveau_i2c_dtor,
146 .init = _nouveau_i2c_init, 130 .init = _nouveau_i2c_init,
147 .fini = _nouveau_i2c_fini, 131 .fini = _nouveau_i2c_fini,
148 }, 132 },
149}; 133 .sclass = nv50_i2c_sclass,
134 .pad_x = &nv04_i2c_pad_oclass,
135}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h
index 4e5ba48ebf5a..5d2a77421c74 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h
@@ -1,7 +1,7 @@
1#ifndef __NV50_I2C_H__ 1#ifndef __NV50_I2C_H__
2#define __NV50_I2C_H__ 2#define __NV50_I2C_H__
3 3
4#include <subdev/i2c.h> 4#include "priv.h"
5 5
6struct nv50_i2c_priv { 6struct nv50_i2c_priv {
7 struct nouveau_i2c base; 7 struct nouveau_i2c base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
index df6d3e4b68be..f59c3a255462 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
@@ -24,6 +24,36 @@
24 24
25#include "nv50.h" 25#include "nv50.h"
26 26
27void
28nv94_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
29{
30 u32 intr = nv_rd32(i2c, 0x00e06c);
31 u32 stat = nv_rd32(i2c, 0x00e068) & intr, i;
32 for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
33 if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
34 if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
35 if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
36 if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
37 }
38 nv_wr32(i2c, 0x00e06c, intr);
39}
40
41void
42nv94_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data)
43{
44 u32 temp = nv_rd32(i2c, 0x00e068), i;
45 for (i = 0; i < 8; i++) {
46 if (mask & (1 << i)) {
47 if (!(data & (1 << i))) {
48 temp &= ~(type << (i * 4));
49 continue;
50 }
51 temp |= type << (i * 4);
52 }
53 }
54 nv_wr32(i2c, 0x00e068, temp);
55}
56
27#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args) 57#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
28#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args) 58#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
29 59
@@ -69,7 +99,8 @@ auxch_init(struct nouveau_i2c *aux, int ch)
69} 99}
70 100
71int 101int
72nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) 102nv94_aux(struct nouveau_i2c_port *base, bool retry,
103 u8 type, u32 addr, u8 *data, u8 size)
73{ 104{
74 struct nouveau_i2c *aux = nouveau_i2c(base); 105 struct nouveau_i2c *aux = nouveau_i2c(base);
75 struct nv50_i2c_port *port = (void *)base; 106 struct nv50_i2c_port *port = (void *)base;
@@ -105,9 +136,8 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
105 ctrl |= size - 1; 136 ctrl |= size - 1;
106 nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr); 137 nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
107 138
108 /* retry transaction a number of times on failure... */ 139 /* (maybe) retry transaction a number of times on failure... */
109 ret = -EREMOTEIO; 140 for (retries = 0; !ret && retries < 32; retries++) {
110 for (retries = 0; retries < 32; retries++) {
111 /* reset, and delay a while if this is a retry */ 141 /* reset, and delay a while if this is a retry */
112 nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); 142 nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
113 nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); 143 nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
@@ -123,16 +153,21 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
123 udelay(1); 153 udelay(1);
124 if (!timeout--) { 154 if (!timeout--) {
125 AUX_ERR("tx req timeout 0x%08x\n", ctrl); 155 AUX_ERR("tx req timeout 0x%08x\n", ctrl);
156 ret = -EIO;
126 goto out; 157 goto out;
127 } 158 }
128 } while (ctrl & 0x00010000); 159 } while (ctrl & 0x00010000);
160 ret = 1;
129 161
130 /* read status, and check if transaction completed ok */ 162 /* read status, and check if transaction completed ok */
131 stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0); 163 stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
132 if (!(stat & 0x000f0f00)) { 164 if ((stat & 0x000f0000) == 0x00080000 ||
133 ret = 0; 165 (stat & 0x000f0000) == 0x00020000)
134 break; 166 ret = retry ? 0 : 1;
135 } 167 if ((stat & 0x00000100))
168 ret = -ETIMEDOUT;
169 if ((stat & 0x00000e00))
170 ret = -EIO;
136 171
137 AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); 172 AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
138 } 173 }
@@ -147,29 +182,11 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
147 182
148out: 183out:
149 auxch_fini(aux, ch); 184 auxch_fini(aux, ch);
150 return ret; 185 return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
151}
152
153void
154nv94_i2c_acquire(struct nouveau_i2c_port *base)
155{
156 struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
157 struct nv50_i2c_port *port = (void *)base;
158 if (port->ctrl) {
159 nv_mask(priv, port->ctrl + 0x0c, 0x00000001, 0x00000000);
160 nv_mask(priv, port->ctrl + 0x00, 0x0000f003, port->data);
161 }
162}
163
164void
165nv94_i2c_release(struct nouveau_i2c_port *base)
166{
167} 186}
168 187
169static const struct nouveau_i2c_func 188static const struct nouveau_i2c_func
170nv94_i2c_func = { 189nv94_i2c_func = {
171 .acquire = nv94_i2c_acquire,
172 .release = nv94_i2c_release,
173 .drive_scl = nv50_i2c_drive_scl, 190 .drive_scl = nv50_i2c_drive_scl,
174 .drive_sda = nv50_i2c_drive_sda, 191 .drive_sda = nv50_i2c_drive_sda,
175 .sense_scl = nv50_i2c_sense_scl, 192 .sense_scl = nv50_i2c_sense_scl,
@@ -206,8 +223,6 @@ nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
206 223
207static const struct nouveau_i2c_func 224static const struct nouveau_i2c_func
208nv94_aux_func = { 225nv94_aux_func = {
209 .acquire = nv94_i2c_acquire,
210 .release = nv94_i2c_release,
211 .aux = nv94_aux, 226 .aux = nv94_aux,
212}; 227};
213 228
@@ -227,6 +242,7 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
227 if (ret) 242 if (ret)
228 return ret; 243 return ret;
229 244
245 port->base.aux = info->drive;
230 port->addr = info->drive; 246 port->addr = info->drive;
231 if (info->share != DCB_I2C_UNUSED) { 247 if (info->share != DCB_I2C_UNUSED) {
232 port->ctrl = 0x00e500 + (info->drive * 0x50); 248 port->ctrl = 0x00e500 + (info->drive * 0x50);
@@ -257,29 +273,19 @@ nv94_i2c_sclass[] = {
257 {} 273 {}
258}; 274};
259 275
260static int 276struct nouveau_oclass *
261nv94_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 277nv94_i2c_oclass = &(struct nouveau_i2c_impl) {
262 struct nouveau_oclass *oclass, void *data, u32 size, 278 .base.handle = NV_SUBDEV(I2C, 0x94),
263 struct nouveau_object **pobject) 279 .base.ofuncs = &(struct nouveau_ofuncs) {
264{ 280 .ctor = _nouveau_i2c_ctor,
265 struct nv50_i2c_priv *priv;
266 int ret;
267
268 ret = nouveau_i2c_create(parent, engine, oclass, nv94_i2c_sclass, &priv);
269 *pobject = nv_object(priv);
270 if (ret)
271 return ret;
272
273 return 0;
274}
275
276struct nouveau_oclass
277nv94_i2c_oclass = {
278 .handle = NV_SUBDEV(I2C, 0x94),
279 .ofuncs = &(struct nouveau_ofuncs) {
280 .ctor = nv94_i2c_ctor,
281 .dtor = _nouveau_i2c_dtor, 281 .dtor = _nouveau_i2c_dtor,
282 .init = _nouveau_i2c_init, 282 .init = _nouveau_i2c_init,
283 .fini = _nouveau_i2c_fini, 283 .fini = _nouveau_i2c_fini,
284 }, 284 },
285}; 285 .sclass = nv94_i2c_sclass,
286 .pad_x = &nv04_i2c_pad_oclass,
287 .pad_s = &nv94_i2c_pad_oclass,
288 .aux = 4,
289 .aux_stat = nv94_aux_stat,
290 .aux_mask = nv94_aux_mask,
291}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c
index 29967d30f97c..364ddb1c5f03 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c
@@ -42,8 +42,6 @@ nvd0_i2c_sense_sda(struct nouveau_i2c_port *base)
42 42
43static const struct nouveau_i2c_func 43static const struct nouveau_i2c_func
44nvd0_i2c_func = { 44nvd0_i2c_func = {
45 .acquire = nv94_i2c_acquire,
46 .release = nv94_i2c_release,
47 .drive_scl = nv50_i2c_drive_scl, 45 .drive_scl = nv50_i2c_drive_scl,
48 .drive_sda = nv50_i2c_drive_sda, 46 .drive_sda = nv50_i2c_drive_sda,
49 .sense_scl = nvd0_i2c_sense_scl, 47 .sense_scl = nvd0_i2c_sense_scl,
@@ -75,7 +73,7 @@ nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
75 return 0; 73 return 0;
76} 74}
77 75
78static struct nouveau_oclass 76struct nouveau_oclass
79nvd0_i2c_sclass[] = { 77nvd0_i2c_sclass[] = {
80 { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), 78 { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
81 .ofuncs = &(struct nouveau_ofuncs) { 79 .ofuncs = &(struct nouveau_ofuncs) {
@@ -96,29 +94,19 @@ nvd0_i2c_sclass[] = {
96 {} 94 {}
97}; 95};
98 96
99static int 97struct nouveau_oclass *
100nvd0_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 98nvd0_i2c_oclass = &(struct nouveau_i2c_impl) {
101 struct nouveau_oclass *oclass, void *data, u32 size, 99 .base.handle = NV_SUBDEV(I2C, 0xd0),
102 struct nouveau_object **pobject) 100 .base.ofuncs = &(struct nouveau_ofuncs) {
103{ 101 .ctor = _nouveau_i2c_ctor,
104 struct nv50_i2c_priv *priv;
105 int ret;
106
107 ret = nouveau_i2c_create(parent, engine, oclass, nvd0_i2c_sclass, &priv);
108 *pobject = nv_object(priv);
109 if (ret)
110 return ret;
111
112 return 0;
113}
114
115struct nouveau_oclass
116nvd0_i2c_oclass = {
117 .handle = NV_SUBDEV(I2C, 0xd0),
118 .ofuncs = &(struct nouveau_ofuncs) {
119 .ctor = nvd0_i2c_ctor,
120 .dtor = _nouveau_i2c_dtor, 102 .dtor = _nouveau_i2c_dtor,
121 .init = _nouveau_i2c_init, 103 .init = _nouveau_i2c_init,
122 .fini = _nouveau_i2c_fini, 104 .fini = _nouveau_i2c_fini,
123 }, 105 },
124}; 106 .sclass = nvd0_i2c_sclass,
107 .pad_x = &nv04_i2c_pad_oclass,
108 .pad_s = &nv94_i2c_pad_oclass,
109 .aux = 4,
110 .aux_stat = nv94_aux_stat,
111 .aux_mask = nv94_aux_mask,
112}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c
new file mode 100644
index 000000000000..cae77e1ad8dc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c
@@ -0,0 +1,72 @@
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 "nv50.h"
26
27static void
28nve0_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
29{
30 u32 intr = nv_rd32(i2c, 0x00dc60);
31 u32 stat = nv_rd32(i2c, 0x00dc68) & intr, i;
32 for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
33 if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
34 if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
35 if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
36 if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
37 }
38 nv_wr32(i2c, 0x00dc60, intr);
39}
40
41static void
42nve0_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data)
43{
44 u32 temp = nv_rd32(i2c, 0x00dc68), i;
45 for (i = 0; i < 8; i++) {
46 if (mask & (1 << i)) {
47 if (!(data & (1 << i))) {
48 temp &= ~(type << (i * 4));
49 continue;
50 }
51 temp |= type << (i * 4);
52 }
53 }
54 nv_wr32(i2c, 0x00dc68, temp);
55}
56
57struct nouveau_oclass *
58nve0_i2c_oclass = &(struct nouveau_i2c_impl) {
59 .base.handle = NV_SUBDEV(I2C, 0xe0),
60 .base.ofuncs = &(struct nouveau_ofuncs) {
61 .ctor = _nouveau_i2c_ctor,
62 .dtor = _nouveau_i2c_dtor,
63 .init = _nouveau_i2c_init,
64 .fini = _nouveau_i2c_fini,
65 },
66 .sclass = nvd0_i2c_sclass,
67 .pad_x = &nv04_i2c_pad_oclass,
68 .pad_s = &nv94_i2c_pad_oclass,
69 .aux = 4,
70 .aux_stat = nve0_aux_stat,
71 .aux_mask = nve0_aux_mask,
72}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c
new file mode 100644
index 000000000000..e9e412477c12
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c
@@ -0,0 +1,84 @@
1/*
2 * Copyright 2014 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 "pad.h"
26
27int
28_nvkm_i2c_pad_fini(struct nouveau_object *object, bool suspend)
29{
30 struct nvkm_i2c_pad *pad = (void *)object;
31 DBG("-> NULL\n");
32 pad->port = NULL;
33 return nouveau_object_fini(&pad->base, suspend);
34}
35
36int
37_nvkm_i2c_pad_init(struct nouveau_object *object)
38{
39 struct nvkm_i2c_pad *pad = (void *)object;
40 DBG("-> PORT:%02x\n", pad->next->index);
41 pad->port = pad->next;
42 return nouveau_object_init(&pad->base);
43}
44
45int
46nvkm_i2c_pad_create_(struct nouveau_object *parent,
47 struct nouveau_object *engine,
48 struct nouveau_oclass *oclass, int index,
49 int size, void **pobject)
50{
51 struct nouveau_i2c *i2c = (void *)engine;
52 struct nouveau_i2c_port *port;
53 struct nvkm_i2c_pad *pad;
54 int ret;
55
56 list_for_each_entry(port, &i2c->ports, head) {
57 pad = nvkm_i2c_pad(port);
58 if (pad->index == index) {
59 atomic_inc(&nv_object(pad)->refcount);
60 *pobject = pad;
61 return 1;
62 }
63 }
64
65 ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject);
66 pad = *pobject;
67 if (ret)
68 return ret;
69
70 pad->index = index;
71 return 0;
72}
73
74int
75_nvkm_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
76 struct nouveau_oclass *oclass, void *data, u32 index,
77 struct nouveau_object **pobject)
78{
79 struct nvkm_i2c_pad *pad;
80 int ret;
81 ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
82 *pobject = nv_object(pad);
83 return ret;
84}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h
new file mode 100644
index 000000000000..452ac10c3004
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h
@@ -0,0 +1,58 @@
1#ifndef __NVKM_I2C_PAD_H__
2#define __NVKM_I2C_PAD_H__
3
4#include "priv.h"
5
6struct nvkm_i2c_pad {
7 struct nouveau_object base;
8 int index;
9 struct nouveau_i2c_port *port;
10 struct nouveau_i2c_port *next;
11};
12
13static inline struct nvkm_i2c_pad *
14nvkm_i2c_pad(struct nouveau_i2c_port *port)
15{
16 struct nouveau_object *pad = nv_object(port);
17 while (pad->parent)
18 pad = pad->parent;
19 return (void *)pad;
20}
21
22#define nvkm_i2c_pad_create(p,e,o,i,d) \
23 nvkm_i2c_pad_create_((p), (e), (o), (i), sizeof(**d), (void **)d)
24#define nvkm_i2c_pad_destroy(p) ({ \
25 struct nvkm_i2c_pad *_p = (p); \
26 _nvkm_i2c_pad_dtor(nv_object(_p)); \
27})
28#define nvkm_i2c_pad_init(p) ({ \
29 struct nvkm_i2c_pad *_p = (p); \
30 _nvkm_i2c_pad_init(nv_object(_p)); \
31})
32#define nvkm_i2c_pad_fini(p,s) ({ \
33 struct nvkm_i2c_pad *_p = (p); \
34 _nvkm_i2c_pad_fini(nv_object(_p), (s)); \
35})
36
37int nvkm_i2c_pad_create_(struct nouveau_object *, struct nouveau_object *,
38 struct nouveau_oclass *, int index, int, void **);
39
40int _nvkm_i2c_pad_ctor(struct nouveau_object *, struct nouveau_object *,
41 struct nouveau_oclass *, void *, u32,
42 struct nouveau_object **);
43#define _nvkm_i2c_pad_dtor nouveau_object_destroy
44int _nvkm_i2c_pad_init(struct nouveau_object *);
45int _nvkm_i2c_pad_fini(struct nouveau_object *, bool);
46
47#ifndef MSG
48#define MSG(l,f,a...) do { \
49 struct nvkm_i2c_pad *_pad = (void *)pad; \
50 nv_##l(nv_object(_pad)->engine, "PAD:%c:%02x: "f, \
51 _pad->index >= 0x100 ? 'X' : 'S', \
52 _pad->index >= 0x100 ? _pad->index - 0x100 : _pad->index, ##a); \
53} while(0)
54#define DBG(f,a...) MSG(debug, f, ##a)
55#define ERR(f,a...) MSG(error, f, ##a)
56#endif
57
58#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c
new file mode 100644
index 000000000000..2c4b61296dd1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c
@@ -0,0 +1,35 @@
1/*
2 * Copyright 2014 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 "pad.h"
26
27struct nouveau_oclass
28nv04_i2c_pad_oclass = {
29 .ofuncs = &(struct nouveau_ofuncs) {
30 .ctor = _nvkm_i2c_pad_ctor,
31 .dtor = _nvkm_i2c_pad_dtor,
32 .init = _nvkm_i2c_pad_init,
33 .fini = _nvkm_i2c_pad_fini,
34 },
35};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c
new file mode 100644
index 000000000000..0dc6753014f0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c
@@ -0,0 +1,86 @@
1/*
2 * Copyright 2014 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 "pad.h"
26
27struct nv94_i2c_pad {
28 struct nvkm_i2c_pad base;
29 int addr;
30};
31
32static int
33nv94_i2c_pad_fini(struct nouveau_object *object, bool suspend)
34{
35 struct nouveau_i2c *i2c = (void *)object->engine;
36 struct nv94_i2c_pad *pad = (void *)object;
37 nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000001);
38 return nvkm_i2c_pad_fini(&pad->base, suspend);
39}
40
41static int
42nv94_i2c_pad_init(struct nouveau_object *object)
43{
44 struct nouveau_i2c *i2c = (void *)object->engine;
45 struct nv94_i2c_pad *pad = (void *)object;
46
47 switch (nv_oclass(pad->base.next)->handle) {
48 case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX):
49 nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x00000002);
50 break;
51 case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT):
52 default:
53 nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001);
54 break;
55 }
56
57 nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000000);
58 return nvkm_i2c_pad_init(&pad->base);
59}
60
61static int
62nv94_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
63 struct nouveau_oclass *oclass, void *data, u32 index,
64 struct nouveau_object **pobject)
65{
66 struct nv94_i2c_pad *pad;
67 int ret;
68
69 ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
70 *pobject = nv_object(pad);
71 if (ret)
72 return ret;
73
74 pad->addr = index * 0x50;;
75 return 0;
76}
77
78struct nouveau_oclass
79nv94_i2c_pad_oclass = {
80 .ofuncs = &(struct nouveau_ofuncs) {
81 .ctor = nv94_i2c_pad_ctor,
82 .dtor = _nvkm_i2c_pad_dtor,
83 .init = nv94_i2c_pad_init,
84 .fini = nv94_i2c_pad_fini,
85 },
86};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h
new file mode 100644
index 000000000000..a8ff6e077af5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h
@@ -0,0 +1,15 @@
1#ifndef __NVKM_I2C_PORT_H__
2#define __NVKM_I2C_PORT_H__
3
4#include "priv.h"
5
6#ifndef MSG
7#define MSG(l,f,a...) do { \
8 struct nouveau_i2c_port *_port = (void *)port; \
9 nv_##l(nv_object(_port)->engine, "PORT:%02x: "f, _port->index, ##a); \
10} while(0)
11#define DBG(f,a...) MSG(debug, f, ##a)
12#define ERR(f,a...) MSG(error, f, ##a)
13#endif
14
15#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h
new file mode 100644
index 000000000000..780090b6425a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h
@@ -0,0 +1,85 @@
1#ifndef __NVKM_I2C_H__
2#define __NVKM_I2C_H__
3
4#include <subdev/i2c.h>
5
6extern struct nouveau_oclass nv04_i2c_pad_oclass;
7extern struct nouveau_oclass nv94_i2c_pad_oclass;
8
9#define nouveau_i2c_port_create(p,e,o,i,a,f,d) \
10 nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f), \
11 sizeof(**d), (void **)d)
12#define nouveau_i2c_port_destroy(p) ({ \
13 struct nouveau_i2c_port *port = (p); \
14 _nouveau_i2c_port_dtor(nv_object(i2c)); \
15})
16#define nouveau_i2c_port_init(p) \
17 nouveau_object_init(&(p)->base)
18#define nouveau_i2c_port_fini(p,s) \
19 nouveau_object_fini(&(p)->base, (s))
20
21int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *,
22 struct nouveau_oclass *, u8,
23 const struct i2c_algorithm *,
24 const struct nouveau_i2c_func *,
25 int, void **);
26void _nouveau_i2c_port_dtor(struct nouveau_object *);
27#define _nouveau_i2c_port_init nouveau_object_init
28int _nouveau_i2c_port_fini(struct nouveau_object *, bool);
29
30#define nouveau_i2c_create(p,e,o,d) \
31 nouveau_i2c_create_((p), (e), (o), sizeof(**d), (void **)d)
32#define nouveau_i2c_destroy(p) ({ \
33 struct nouveau_i2c *i2c = (p); \
34 _nouveau_i2c_dtor(nv_object(i2c)); \
35})
36#define nouveau_i2c_init(p) ({ \
37 struct nouveau_i2c *i2c = (p); \
38 _nouveau_i2c_init(nv_object(i2c)); \
39})
40#define nouveau_i2c_fini(p,s) ({ \
41 struct nouveau_i2c *i2c = (p); \
42 _nouveau_i2c_fini(nv_object(i2c), (s)); \
43})
44
45int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *,
46 struct nouveau_oclass *, int, void **);
47int _nouveau_i2c_ctor(struct nouveau_object *, struct nouveau_object *,
48 struct nouveau_oclass *, void *, u32,
49 struct nouveau_object **);
50void _nouveau_i2c_dtor(struct nouveau_object *);
51int _nouveau_i2c_init(struct nouveau_object *);
52int _nouveau_i2c_fini(struct nouveau_object *, bool);
53
54extern struct nouveau_oclass nouveau_anx9805_sclass[];
55extern struct nouveau_oclass nvd0_i2c_sclass[];
56
57extern const struct i2c_algorithm nouveau_i2c_bit_algo;
58extern const struct i2c_algorithm nouveau_i2c_aux_algo;
59
60struct nouveau_i2c_impl {
61 struct nouveau_oclass base;
62
63 /* supported i2c port classes */
64 struct nouveau_oclass *sclass;
65 struct nouveau_oclass *pad_x;
66 struct nouveau_oclass *pad_s;
67
68 /* number of native dp aux channels present */
69 int aux;
70
71 /* read and ack pending interrupts, returning only data
72 * for ports that have not been masked off, while still
73 * performing the ack for anything that was pending.
74 */
75 void (*aux_stat)(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
76
77 /* mask on/off interrupt types for a given set of auxch
78 */
79 void (*aux_mask)(struct nouveau_i2c *, u32, u32, u32);
80};
81
82void nv94_aux_stat(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
83void nv94_aux_mask(struct nouveau_i2c *, u32, u32, u32);
84
85#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
index 90d8bf8ce0dc..9ca93e2718f7 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
@@ -34,7 +34,8 @@ nv50_mc_intr[] = {
34 { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */ 34 { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */
35 { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */ 35 { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */
36 { 0x00100000, NVDEV_SUBDEV_TIMER }, 36 { 0x00100000, NVDEV_SUBDEV_TIMER },
37 { 0x00200000, NVDEV_SUBDEV_GPIO }, 37 { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */
38 { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */
38 { 0x10000000, NVDEV_SUBDEV_BUS }, 39 { 0x10000000, NVDEV_SUBDEV_BUS },
39 { 0x80000000, NVDEV_ENGINE_SW }, 40 { 0x80000000, NVDEV_ENGINE_SW },
40 { 0x0002d101, NVDEV_SUBDEV_FB }, 41 { 0x0002d101, NVDEV_SUBDEV_FB },
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
index 95b3d35388a8..3c76d9038f38 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
@@ -36,7 +36,8 @@ nv98_mc_intr[] = {
36 { 0x00040000, NVDEV_SUBDEV_PWR }, /* NVA3:NVC0 */ 36 { 0x00040000, NVDEV_SUBDEV_PWR }, /* NVA3:NVC0 */
37 { 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */ 37 { 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */
38 { 0x00100000, NVDEV_SUBDEV_TIMER }, 38 { 0x00100000, NVDEV_SUBDEV_TIMER },
39 { 0x00200000, NVDEV_SUBDEV_GPIO }, 39 { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */
40 { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */
40 { 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */ 41 { 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */
41 { 0x10000000, NVDEV_SUBDEV_BUS }, 42 { 0x10000000, NVDEV_SUBDEV_BUS },
42 { 0x80000000, NVDEV_ENGINE_SW }, 43 { 0x80000000, NVDEV_ENGINE_SW },
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
index ac7f99a15fa7..f9c6a678b47d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
@@ -38,7 +38,8 @@ nvc0_mc_intr[] = {
38 { 0x00040000, NVDEV_SUBDEV_THERM }, 38 { 0x00040000, NVDEV_SUBDEV_THERM },
39 { 0x00020000, NVDEV_ENGINE_VP }, 39 { 0x00020000, NVDEV_ENGINE_VP },
40 { 0x00100000, NVDEV_SUBDEV_TIMER }, 40 { 0x00100000, NVDEV_SUBDEV_TIMER },
41 { 0x00200000, NVDEV_SUBDEV_GPIO }, 41 { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */
42 { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */
42 { 0x01000000, NVDEV_SUBDEV_PWR }, 43 { 0x01000000, NVDEV_SUBDEV_PWR },
43 { 0x02000000, NVDEV_SUBDEV_LTCG }, 44 { 0x02000000, NVDEV_SUBDEV_LTCG },
44 { 0x08000000, NVDEV_SUBDEV_FB }, 45 { 0x08000000, NVDEV_SUBDEV_FB },
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c
index 64f8b4702bf7..fcaabe8456e3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c
@@ -150,7 +150,7 @@ mxm_dcb_sanitise_entry(struct nouveau_bios *bios, void *data, int idx, u16 pdcb)
150 * common example is DP->eDP. 150 * common example is DP->eDP.
151 */ 151 */
152 conn = bios->data; 152 conn = bios->data;
153 conn += dcb_conn(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len); 153 conn += nvbios_connEe(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len);
154 type = conn[0]; 154 type = conn[0];
155 switch (ctx.desc.conn_type) { 155 switch (ctx.desc.conn_type) {
156 case 0x01: /* LVDS */ 156 case 0x01: /* LVDS */
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 6ecea9b2b15a..1fa222e8f007 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -44,6 +44,7 @@
44 44
45#include <subdev/i2c.h> 45#include <subdev/i2c.h>
46#include <subdev/gpio.h> 46#include <subdev/gpio.h>
47#include <engine/disp.h>
47 48
48MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); 49MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
49static int nouveau_tv_disable = 0; 50static int nouveau_tv_disable = 0;
@@ -75,7 +76,8 @@ find_encoder(struct drm_connector *connector, int type)
75 continue; 76 continue;
76 nv_encoder = nouveau_encoder(obj_to_encoder(obj)); 77 nv_encoder = nouveau_encoder(obj_to_encoder(obj));
77 78
78 if (type == DCB_OUTPUT_ANY || nv_encoder->dcb->type == type) 79 if (type == DCB_OUTPUT_ANY ||
80 (nv_encoder->dcb && nv_encoder->dcb->type == type))
79 return nv_encoder; 81 return nv_encoder;
80 } 82 }
81 83
@@ -100,22 +102,24 @@ static void
100nouveau_connector_destroy(struct drm_connector *connector) 102nouveau_connector_destroy(struct drm_connector *connector)
101{ 103{
102 struct nouveau_connector *nv_connector = nouveau_connector(connector); 104 struct nouveau_connector *nv_connector = nouveau_connector(connector);
103 nouveau_event_ref(NULL, &nv_connector->hpd_func); 105 nouveau_event_ref(NULL, &nv_connector->hpd);
104 kfree(nv_connector->edid); 106 kfree(nv_connector->edid);
105 drm_sysfs_connector_remove(connector); 107 drm_sysfs_connector_remove(connector);
106 drm_connector_cleanup(connector); 108 drm_connector_cleanup(connector);
109 if (nv_connector->aux.transfer)
110 drm_dp_aux_unregister(&nv_connector->aux);
107 kfree(connector); 111 kfree(connector);
108} 112}
109 113
110static struct nouveau_i2c_port * 114static struct nouveau_encoder *
111nouveau_connector_ddc_detect(struct drm_connector *connector, 115nouveau_connector_ddc_detect(struct drm_connector *connector)
112 struct nouveau_encoder **pnv_encoder)
113{ 116{
114 struct drm_device *dev = connector->dev; 117 struct drm_device *dev = connector->dev;
115 struct nouveau_connector *nv_connector = nouveau_connector(connector); 118 struct nouveau_connector *nv_connector = nouveau_connector(connector);
116 struct nouveau_drm *drm = nouveau_drm(dev); 119 struct nouveau_drm *drm = nouveau_drm(dev);
117 struct nouveau_gpio *gpio = nouveau_gpio(drm->device); 120 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
118 struct nouveau_i2c_port *port = NULL; 121 struct nouveau_encoder *nv_encoder;
122 struct drm_mode_object *obj;
119 int i, panel = -ENODEV; 123 int i, panel = -ENODEV;
120 124
121 /* eDP panels need powering on by us (if the VBIOS doesn't default it 125 /* eDP panels need powering on by us (if the VBIOS doesn't default it
@@ -130,13 +134,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
130 } 134 }
131 } 135 }
132 136
133 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 137 for (i = 0; nv_encoder = NULL, i < DRM_CONNECTOR_MAX_ENCODER; i++) {
134 struct nouveau_encoder *nv_encoder; 138 int id = connector->encoder_ids[i];
135 struct drm_mode_object *obj; 139 if (id == 0)
136 int id;
137
138 id = connector->encoder_ids[i];
139 if (!id)
140 break; 140 break;
141 141
142 obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); 142 obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
@@ -144,22 +144,24 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
144 continue; 144 continue;
145 nv_encoder = nouveau_encoder(obj_to_encoder(obj)); 145 nv_encoder = nouveau_encoder(obj_to_encoder(obj));
146 146
147 port = nv_encoder->i2c; 147 if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
148 if (port && nv_probe_i2c(port, 0x50)) { 148 int ret = nouveau_dp_detect(nv_encoder);
149 *pnv_encoder = nv_encoder; 149 if (ret == 0)
150 break; 150 break;
151 } else
152 if (nv_encoder->i2c) {
153 if (nv_probe_i2c(nv_encoder->i2c, 0x50))
154 break;
151 } 155 }
152
153 port = NULL;
154 } 156 }
155 157
156 /* eDP panel not detected, restore panel power GPIO to previous 158 /* eDP panel not detected, restore panel power GPIO to previous
157 * state to avoid confusing the SOR for other output types. 159 * state to avoid confusing the SOR for other output types.
158 */ 160 */
159 if (!port && panel == 0) 161 if (!nv_encoder && panel == 0)
160 gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel); 162 gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel);
161 163
162 return port; 164 return nv_encoder;
163} 165}
164 166
165static struct nouveau_encoder * 167static struct nouveau_encoder *
@@ -258,8 +260,8 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
258 if (ret < 0 && ret != -EACCES) 260 if (ret < 0 && ret != -EACCES)
259 return conn_status; 261 return conn_status;
260 262
261 i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); 263 nv_encoder = nouveau_connector_ddc_detect(connector);
262 if (i2c) { 264 if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
263 nv_connector->edid = drm_get_edid(connector, &i2c->adapter); 265 nv_connector->edid = drm_get_edid(connector, &i2c->adapter);
264 drm_mode_connector_update_edid_property(connector, 266 drm_mode_connector_update_edid_property(connector,
265 nv_connector->edid); 267 nv_connector->edid);
@@ -269,14 +271,6 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
269 goto detect_analog; 271 goto detect_analog;
270 } 272 }
271 273
272 if (nv_encoder->dcb->type == DCB_OUTPUT_DP &&
273 !nouveau_dp_detect(to_drm_encoder(nv_encoder))) {
274 NV_ERROR(drm, "Detected %s, but failed init\n",
275 connector->name);
276 conn_status = connector_status_disconnected;
277 goto out;
278 }
279
280 /* Override encoder type for DVI-I based on whether EDID 274 /* Override encoder type for DVI-I based on whether EDID
281 * says the display is digital or analog, both use the 275 * says the display is digital or analog, both use the
282 * same i2c channel so the value returned from ddc_detect 276 * same i2c channel so the value returned from ddc_detect
@@ -912,33 +906,103 @@ nouveau_connector_funcs_lvds = {
912}; 906};
913 907
914static void 908static void
909nouveau_connector_dp_dpms(struct drm_connector *connector, int mode)
910{
911 struct nouveau_encoder *nv_encoder = NULL;
912
913 if (connector->encoder)
914 nv_encoder = nouveau_encoder(connector->encoder);
915 if (nv_encoder && nv_encoder->dcb &&
916 nv_encoder->dcb->type == DCB_OUTPUT_DP) {
917 if (mode == DRM_MODE_DPMS_ON) {
918 u8 data = DP_SET_POWER_D0;
919 nv_wraux(nv_encoder->i2c, DP_SET_POWER, &data, 1);
920 usleep_range(1000, 2000);
921 } else {
922 u8 data = DP_SET_POWER_D3;
923 nv_wraux(nv_encoder->i2c, DP_SET_POWER, &data, 1);
924 }
925 }
926
927 drm_helper_connector_dpms(connector, mode);
928}
929
930static const struct drm_connector_funcs
931nouveau_connector_funcs_dp = {
932 .dpms = nouveau_connector_dp_dpms,
933 .save = NULL,
934 .restore = NULL,
935 .detect = nouveau_connector_detect,
936 .destroy = nouveau_connector_destroy,
937 .fill_modes = drm_helper_probe_single_connector_modes,
938 .set_property = nouveau_connector_set_property,
939 .force = nouveau_connector_force
940};
941
942static void
915nouveau_connector_hotplug_work(struct work_struct *work) 943nouveau_connector_hotplug_work(struct work_struct *work)
916{ 944{
917 struct nouveau_connector *nv_connector = 945 struct nouveau_connector *nv_connector =
918 container_of(work, struct nouveau_connector, hpd_work); 946 container_of(work, typeof(*nv_connector), work);
919 struct drm_connector *connector = &nv_connector->base; 947 struct drm_connector *connector = &nv_connector->base;
920 struct drm_device *dev = connector->dev; 948 struct nouveau_drm *drm = nouveau_drm(connector->dev);
921 struct nouveau_drm *drm = nouveau_drm(dev); 949 const char *name = connector->name;
922 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
923 bool plugged = gpio->get(gpio, 0, nv_connector->hpd.func, 0xff);
924 950
925 NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", 951 if (nv_connector->status & NVKM_HPD_IRQ) {
926 connector->name); 952 } else {
953 bool plugged = (nv_connector->status != NVKM_HPD_UNPLUG);
927 954
928 if (plugged) 955 NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
929 drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
930 else
931 drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
932 956
933 drm_helper_hpd_irq_event(dev); 957 if (plugged)
958 drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
959 else
960 drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
961 drm_helper_hpd_irq_event(connector->dev);
962 }
963
964 nouveau_event_get(nv_connector->hpd);
934} 965}
935 966
936static int 967static int
937nouveau_connector_hotplug(void *data, int index) 968nouveau_connector_hotplug(void *data, u32 type, int index)
938{ 969{
939 struct nouveau_connector *nv_connector = data; 970 struct nouveau_connector *nv_connector = data;
940 schedule_work(&nv_connector->hpd_work); 971 nv_connector->status = type;
941 return NVKM_EVENT_KEEP; 972 schedule_work(&nv_connector->work);
973 return NVKM_EVENT_DROP;
974}
975
976static ssize_t
977nouveau_connector_aux_xfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
978{
979 struct nouveau_connector *nv_connector =
980 container_of(aux, typeof(*nv_connector), aux);
981 struct nouveau_encoder *nv_encoder;
982 struct nouveau_i2c_port *port;
983 int ret;
984
985 nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
986 if (!nv_encoder || !(port = nv_encoder->i2c))
987 return -ENODEV;
988 if (WARN_ON(msg->size > 16))
989 return -E2BIG;
990 if (msg->size == 0)
991 return msg->size;
992
993 ret = nouveau_i2c(port)->acquire(port, 0);
994 if (ret)
995 return ret;
996
997 ret = port->func->aux(port, false, msg->request, msg->address,
998 msg->buffer, msg->size);
999 nouveau_i2c(port)->release(port);
1000 if (ret >= 0) {
1001 msg->reply = ret;
1002 return msg->size;
1003 }
1004
1005 return ret;
942} 1006}
943 1007
944static int 1008static int
@@ -974,9 +1038,9 @@ nouveau_connector_create(struct drm_device *dev, int index)
974{ 1038{
975 const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; 1039 const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
976 struct nouveau_drm *drm = nouveau_drm(dev); 1040 struct nouveau_drm *drm = nouveau_drm(dev);
977 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
978 struct nouveau_display *disp = nouveau_display(dev); 1041 struct nouveau_display *disp = nouveau_display(dev);
979 struct nouveau_connector *nv_connector = NULL; 1042 struct nouveau_connector *nv_connector = NULL;
1043 struct nouveau_disp *pdisp = nouveau_disp(drm->device);
980 struct drm_connector *connector; 1044 struct drm_connector *connector;
981 int type, ret = 0; 1045 int type, ret = 0;
982 bool dummy; 1046 bool dummy;
@@ -992,33 +1056,15 @@ nouveau_connector_create(struct drm_device *dev, int index)
992 return ERR_PTR(-ENOMEM); 1056 return ERR_PTR(-ENOMEM);
993 1057
994 connector = &nv_connector->base; 1058 connector = &nv_connector->base;
995 INIT_WORK(&nv_connector->hpd_work, nouveau_connector_hotplug_work);
996 nv_connector->index = index; 1059 nv_connector->index = index;
997 1060
998 /* attempt to parse vbios connector type and hotplug gpio */ 1061 /* attempt to parse vbios connector type and hotplug gpio */
999 nv_connector->dcb = olddcb_conn(dev, index); 1062 nv_connector->dcb = olddcb_conn(dev, index);
1000 if (nv_connector->dcb) { 1063 if (nv_connector->dcb) {
1001 static const u8 hpd[16] = {
1002 0xff, 0x07, 0x08, 0xff, 0xff, 0x51, 0x52, 0xff,
1003 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x5f, 0x60,
1004 };
1005
1006 u32 entry = ROM16(nv_connector->dcb[0]); 1064 u32 entry = ROM16(nv_connector->dcb[0]);
1007 if (olddcb_conntab(dev)[3] >= 4) 1065 if (olddcb_conntab(dev)[3] >= 4)
1008 entry |= (u32)ROM16(nv_connector->dcb[2]) << 16; 1066 entry |= (u32)ROM16(nv_connector->dcb[2]) << 16;
1009 1067
1010 ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)],
1011 DCB_GPIO_UNUSED, &nv_connector->hpd);
1012 if (ret)
1013 nv_connector->hpd.func = DCB_GPIO_UNUSED;
1014
1015 if (nv_connector->hpd.func != DCB_GPIO_UNUSED) {
1016 nouveau_event_new(gpio->events, nv_connector->hpd.line,
1017 nouveau_connector_hotplug,
1018 nv_connector,
1019 &nv_connector->hpd_func);
1020 }
1021
1022 nv_connector->type = nv_connector->dcb[0]; 1068 nv_connector->type = nv_connector->dcb[0];
1023 if (drm_conntype_from_dcb(nv_connector->type) == 1069 if (drm_conntype_from_dcb(nv_connector->type) ==
1024 DRM_MODE_CONNECTOR_Unknown) { 1070 DRM_MODE_CONNECTOR_Unknown) {
@@ -1040,7 +1086,6 @@ nouveau_connector_create(struct drm_device *dev, int index)
1040 } 1086 }
1041 } else { 1087 } else {
1042 nv_connector->type = DCB_CONNECTOR_NONE; 1088 nv_connector->type = DCB_CONNECTOR_NONE;
1043 nv_connector->hpd.func = DCB_GPIO_UNUSED;
1044 } 1089 }
1045 1090
1046 /* no vbios data, or an unknown dcb connector type - attempt to 1091 /* no vbios data, or an unknown dcb connector type - attempt to
@@ -1080,8 +1125,8 @@ nouveau_connector_create(struct drm_device *dev, int index)
1080 } 1125 }
1081 } 1126 }
1082 1127
1083 type = drm_conntype_from_dcb(nv_connector->type); 1128 switch ((type = drm_conntype_from_dcb(nv_connector->type))) {
1084 if (type == DRM_MODE_CONNECTOR_LVDS) { 1129 case DRM_MODE_CONNECTOR_LVDS:
1085 ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy); 1130 ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy);
1086 if (ret) { 1131 if (ret) {
1087 NV_ERROR(drm, "Error parsing LVDS table, disabling\n"); 1132 NV_ERROR(drm, "Error parsing LVDS table, disabling\n");
@@ -1090,8 +1135,23 @@ nouveau_connector_create(struct drm_device *dev, int index)
1090 } 1135 }
1091 1136
1092 funcs = &nouveau_connector_funcs_lvds; 1137 funcs = &nouveau_connector_funcs_lvds;
1093 } else { 1138 break;
1139 case DRM_MODE_CONNECTOR_DisplayPort:
1140 case DRM_MODE_CONNECTOR_eDP:
1141 nv_connector->aux.dev = dev->dev;
1142 nv_connector->aux.transfer = nouveau_connector_aux_xfer;
1143 ret = drm_dp_aux_register(&nv_connector->aux);
1144 if (ret) {
1145 NV_ERROR(drm, "failed to register aux channel\n");
1146 kfree(nv_connector);
1147 return ERR_PTR(ret);
1148 }
1149
1150 funcs = &nouveau_connector_funcs_dp;
1151 break;
1152 default:
1094 funcs = &nouveau_connector_funcs; 1153 funcs = &nouveau_connector_funcs;
1154 break;
1095 } 1155 }
1096 1156
1097 /* defaults, will get overridden in detect() */ 1157 /* defaults, will get overridden in detect() */
@@ -1166,10 +1226,16 @@ nouveau_connector_create(struct drm_device *dev, int index)
1166 break; 1226 break;
1167 } 1227 }
1168 1228
1169 connector->polled = DRM_CONNECTOR_POLL_CONNECT; 1229 ret = nouveau_event_new(pdisp->hpd, NVKM_HPD, index,
1170 if (nv_connector->hpd.func != DCB_GPIO_UNUSED) 1230 nouveau_connector_hotplug,
1231 nv_connector, &nv_connector->hpd);
1232 if (ret)
1233 connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1234 else
1171 connector->polled = DRM_CONNECTOR_POLL_HPD; 1235 connector->polled = DRM_CONNECTOR_POLL_HPD;
1172 1236
1237 INIT_WORK(&nv_connector->work, nouveau_connector_hotplug_work);
1238
1173 drm_sysfs_connector_add(connector); 1239 drm_sysfs_connector_add(connector);
1174 return connector; 1240 return connector;
1175} 1241}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index 264a778f473b..8861b6c579ad 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -28,12 +28,12 @@
28#define __NOUVEAU_CONNECTOR_H__ 28#define __NOUVEAU_CONNECTOR_H__
29 29
30#include <drm/drm_edid.h> 30#include <drm/drm_edid.h>
31#include <drm/drm_dp_helper.h>
31#include "nouveau_crtc.h" 32#include "nouveau_crtc.h"
32 33
33#include <core/event.h> 34#include <core/event.h>
34 35
35#include <subdev/bios.h> 36#include <subdev/bios.h>
36#include <subdev/bios/gpio.h>
37 37
38struct nouveau_i2c_port; 38struct nouveau_i2c_port;
39 39
@@ -67,9 +67,11 @@ struct nouveau_connector {
67 u8 index; 67 u8 index;
68 u8 *dcb; 68 u8 *dcb;
69 69
70 struct dcb_gpio_func hpd; 70 struct nouveau_eventh *hpd;
71 struct work_struct hpd_work; 71 u32 status;
72 struct nouveau_eventh *hpd_func; 72 struct work_struct work;
73
74 struct drm_dp_aux aux;
73 75
74 int dithering_mode; 76 int dithering_mode;
75 int dithering_depth; 77 int dithering_depth;
diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h
index d1e5890784d7..a0534489d23f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_crtc.h
+++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h
@@ -74,7 +74,7 @@ struct nouveau_crtc {
74 74
75static inline struct nouveau_crtc *nouveau_crtc(struct drm_crtc *crtc) 75static inline struct nouveau_crtc *nouveau_crtc(struct drm_crtc *crtc)
76{ 76{
77 return container_of(crtc, struct nouveau_crtc, base); 77 return crtc ? container_of(crtc, struct nouveau_crtc, base) : NULL;
78} 78}
79 79
80static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc) 80static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc)
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 26fbc4f43a5f..26b5647188ef 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -42,7 +42,7 @@
42#include <core/class.h> 42#include <core/class.h>
43 43
44static int 44static int
45nouveau_display_vblank_handler(void *data, int head) 45nouveau_display_vblank_handler(void *data, u32 type, int head)
46{ 46{
47 struct nouveau_drm *drm = data; 47 struct nouveau_drm *drm = data;
48 drm_handle_vblank(drm->dev, head); 48 drm_handle_vblank(drm->dev, head);
@@ -178,7 +178,7 @@ nouveau_display_vblank_init(struct drm_device *dev)
178 return -ENOMEM; 178 return -ENOMEM;
179 179
180 for (i = 0; i < dev->mode_config.num_crtc; i++) { 180 for (i = 0; i < dev->mode_config.num_crtc; i++) {
181 ret = nouveau_event_new(pdisp->vblank, i, 181 ret = nouveau_event_new(pdisp->vblank, 1, i,
182 nouveau_display_vblank_handler, 182 nouveau_display_vblank_handler,
183 drm, &disp->vblank[i]); 183 drm, &disp->vblank[i]);
184 if (ret) { 184 if (ret) {
@@ -393,7 +393,7 @@ nouveau_display_init(struct drm_device *dev)
393 /* enable hotplug interrupts */ 393 /* enable hotplug interrupts */
394 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 394 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
395 struct nouveau_connector *conn = nouveau_connector(connector); 395 struct nouveau_connector *conn = nouveau_connector(connector);
396 if (conn->hpd_func) nouveau_event_get(conn->hpd_func); 396 if (conn->hpd) nouveau_event_get(conn->hpd);
397 } 397 }
398 398
399 return ret; 399 return ret;
@@ -408,7 +408,7 @@ nouveau_display_fini(struct drm_device *dev)
408 /* disable hotplug interrupts */ 408 /* disable hotplug interrupts */
409 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 409 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
410 struct nouveau_connector *conn = nouveau_connector(connector); 410 struct nouveau_connector *conn = nouveau_connector(connector);
411 if (conn->hpd_func) nouveau_event_put(conn->hpd_func); 411 if (conn->hpd) nouveau_event_put(conn->hpd);
412 } 412 }
413 413
414 drm_kms_helper_poll_disable(dev); 414 drm_kms_helper_poll_disable(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 36fd22500569..5675ffc175ae 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -55,11 +55,10 @@ nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch,
55 55
56} 56}
57 57
58bool 58int
59nouveau_dp_detect(struct drm_encoder *encoder) 59nouveau_dp_detect(struct nouveau_encoder *nv_encoder)
60{ 60{
61 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 61 struct drm_device *dev = nv_encoder->base.base.dev;
62 struct drm_device *dev = encoder->dev;
63 struct nouveau_drm *drm = nouveau_drm(dev); 62 struct nouveau_drm *drm = nouveau_drm(dev);
64 struct nouveau_i2c_port *auxch; 63 struct nouveau_i2c_port *auxch;
65 u8 *dpcd = nv_encoder->dp.dpcd; 64 u8 *dpcd = nv_encoder->dp.dpcd;
@@ -67,11 +66,11 @@ nouveau_dp_detect(struct drm_encoder *encoder)
67 66
68 auxch = nv_encoder->i2c; 67 auxch = nv_encoder->i2c;
69 if (!auxch) 68 if (!auxch)
70 return false; 69 return -ENODEV;
71 70
72 ret = nv_rdaux(auxch, DP_DPCD_REV, dpcd, 8); 71 ret = nv_rdaux(auxch, DP_DPCD_REV, dpcd, 8);
73 if (ret) 72 if (ret)
74 return false; 73 return ret;
75 74
76 nv_encoder->dp.link_bw = 27000 * dpcd[1]; 75 nv_encoder->dp.link_bw = 27000 * dpcd[1];
77 nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK; 76 nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
@@ -91,6 +90,5 @@ nouveau_dp_detect(struct drm_encoder *encoder)
91 nv_encoder->dp.link_nr, nv_encoder->dp.link_bw); 90 nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
92 91
93 nouveau_dp_probe_oui(dev, auxch, dpcd); 92 nouveau_dp_probe_oui(dev, auxch, dpcd);
94 93 return 0;
95 return true;
96} 94}
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index 24660c0f713d..5f0e37fc2849 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -46,6 +46,7 @@ struct nouveau_encoder {
46 /* different to drm_encoder.crtc, this reflects what's 46 /* different to drm_encoder.crtc, this reflects what's
47 * actually programmed on the hw, not the proposed crtc */ 47 * actually programmed on the hw, not the proposed crtc */
48 struct drm_crtc *crtc; 48 struct drm_crtc *crtc;
49 u32 ctrl;
49 50
50 struct drm_display_mode mode; 51 struct drm_display_mode mode;
51 int last_dpms; 52 int last_dpms;
@@ -84,9 +85,7 @@ get_slave_funcs(struct drm_encoder *enc)
84} 85}
85 86
86/* nouveau_dp.c */ 87/* nouveau_dp.c */
87bool nouveau_dp_detect(struct drm_encoder *); 88int nouveau_dp_detect(struct nouveau_encoder *);
88void nouveau_dp_dpms(struct drm_encoder *, int mode, u32 datarate,
89 struct nouveau_object *);
90 89
91struct nouveau_connector * 90struct nouveau_connector *
92nouveau_encoder_connector_get(struct nouveau_encoder *encoder); 91nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 90074d620e31..ab5ea3b0d666 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -166,7 +166,7 @@ nouveau_fence_done(struct nouveau_fence *fence)
166} 166}
167 167
168static int 168static int
169nouveau_fence_wait_uevent_handler(void *data, int index) 169nouveau_fence_wait_uevent_handler(void *data, u32 type, int index)
170{ 170{
171 struct nouveau_fence_priv *priv = data; 171 struct nouveau_fence_priv *priv = data;
172 wake_up_all(&priv->waiting); 172 wake_up_all(&priv->waiting);
@@ -183,7 +183,7 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
183 struct nouveau_eventh *handler; 183 struct nouveau_eventh *handler;
184 int ret = 0; 184 int ret = 0;
185 185
186 ret = nouveau_event_new(pfifo->uevent, 0, 186 ret = nouveau_event_new(pfifo->uevent, 1, 0,
187 nouveau_fence_wait_uevent_handler, 187 nouveau_fence_wait_uevent_handler,
188 priv, &handler); 188 priv, &handler);
189 if (ret) 189 if (ret)
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 3c58854aff03..afdf607df3e6 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -26,6 +26,7 @@
26 26
27#include <drm/drmP.h> 27#include <drm/drmP.h>
28#include <drm/drm_crtc_helper.h> 28#include <drm/drm_crtc_helper.h>
29#include <drm/drm_dp_helper.h>
29 30
30#include "nouveau_drm.h" 31#include "nouveau_drm.h"
31#include "nouveau_dma.h" 32#include "nouveau_dma.h"
@@ -1207,6 +1208,7 @@ static void
1207nv50_crtc_disable(struct drm_crtc *crtc) 1208nv50_crtc_disable(struct drm_crtc *crtc)
1208{ 1209{
1209 struct nv50_head *head = nv50_head(crtc); 1210 struct nv50_head *head = nv50_head(crtc);
1211 evo_sync(crtc->dev);
1210 if (head->image) 1212 if (head->image)
1211 nouveau_bo_unpin(head->image); 1213 nouveau_bo_unpin(head->image);
1212 nouveau_bo_ref(NULL, &head->image); 1214 nouveau_bo_ref(NULL, &head->image);
@@ -1700,10 +1702,9 @@ nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
1700} 1702}
1701 1703
1702static void 1704static void
1703nv50_hdmi_disconnect(struct drm_encoder *encoder) 1705nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
1704{ 1706{
1705 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 1707 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1706 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
1707 struct nv50_disp *disp = nv50_disp(encoder->dev); 1708 struct nv50_disp *disp = nv50_disp(encoder->dev);
1708 const u32 moff = (nv_crtc->index << 3) | nv_encoder->or; 1709 const u32 moff = (nv_crtc->index << 3) | nv_encoder->or;
1709 1710
@@ -1722,7 +1723,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
1722 struct drm_device *dev = encoder->dev; 1723 struct drm_device *dev = encoder->dev;
1723 struct nv50_disp *disp = nv50_disp(dev); 1724 struct nv50_disp *disp = nv50_disp(dev);
1724 struct drm_encoder *partner; 1725 struct drm_encoder *partner;
1725 int or = nv_encoder->or; 1726 u32 mthd;
1726 1727
1727 nv_encoder->last_dpms = mode; 1728 nv_encoder->last_dpms = mode;
1728 1729
@@ -1740,7 +1741,17 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
1740 } 1741 }
1741 } 1742 }
1742 1743
1743 nv_call(disp->core, NV50_DISP_SOR_PWR + or, (mode == DRM_MODE_DPMS_ON)); 1744 mthd = (ffs(nv_encoder->dcb->sorconf.link) - 1) << 2;
1745 mthd |= nv_encoder->or;
1746
1747 if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
1748 nv_call(disp->core, NV50_DISP_SOR_PWR | mthd, 1);
1749 mthd |= NV94_DISP_SOR_DP_PWR;
1750 } else {
1751 mthd |= NV50_DISP_SOR_PWR;
1752 }
1753
1754 nv_call(disp->core, mthd, (mode == DRM_MODE_DPMS_ON));
1744} 1755}
1745 1756
1746static bool 1757static bool
@@ -1764,33 +1775,36 @@ nv50_sor_mode_fixup(struct drm_encoder *encoder,
1764} 1775}
1765 1776
1766static void 1777static void
1767nv50_sor_disconnect(struct drm_encoder *encoder) 1778nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data)
1768{ 1779{
1769 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 1780 struct nv50_mast *mast = nv50_mast(nv_encoder->base.base.dev);
1770 struct nv50_mast *mast = nv50_mast(encoder->dev); 1781 u32 temp = (nv_encoder->ctrl & ~mask) | (data & mask), *push;
1771 const int or = nv_encoder->or; 1782 if (temp != nv_encoder->ctrl && (push = evo_wait(mast, 2))) {
1772 u32 *push; 1783 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
1773 1784 evo_mthd(push, 0x0600 + (nv_encoder->or * 0x40), 1);
1774 if (nv_encoder->crtc) { 1785 evo_data(push, (nv_encoder->ctrl = temp));
1775 nv50_crtc_prepare(nv_encoder->crtc); 1786 } else {
1776 1787 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
1777 push = evo_wait(mast, 4); 1788 evo_data(push, (nv_encoder->ctrl = temp));
1778 if (push) {
1779 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
1780 evo_mthd(push, 0x0600 + (or * 0x40), 1);
1781 evo_data(push, 0x00000000);
1782 } else {
1783 evo_mthd(push, 0x0200 + (or * 0x20), 1);
1784 evo_data(push, 0x00000000);
1785 }
1786 evo_kick(push, mast);
1787 } 1789 }
1788 1790 evo_kick(push, mast);
1789 nv50_hdmi_disconnect(encoder);
1790 } 1791 }
1792}
1793
1794static void
1795nv50_sor_disconnect(struct drm_encoder *encoder)
1796{
1797 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1798 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
1791 1799
1792 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; 1800 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1793 nv_encoder->crtc = NULL; 1801 nv_encoder->crtc = NULL;
1802
1803 if (nv_crtc) {
1804 nv50_crtc_prepare(&nv_crtc->base);
1805 nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0);
1806 nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc);
1807 }
1794} 1808}
1795 1809
1796static void 1810static void
@@ -1810,12 +1824,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
1810 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); 1824 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
1811 struct nouveau_connector *nv_connector; 1825 struct nouveau_connector *nv_connector;
1812 struct nvbios *bios = &drm->vbios; 1826 struct nvbios *bios = &drm->vbios;
1813 u32 *push, lvds = 0; 1827 u32 lvds = 0, mask, ctrl;
1814 u8 owner = 1 << nv_crtc->index; 1828 u8 owner = 1 << nv_crtc->index;
1815 u8 proto = 0xf; 1829 u8 proto = 0xf;
1816 u8 depth = 0x0; 1830 u8 depth = 0x0;
1817 1831
1818 nv_connector = nouveau_encoder_connector_get(nv_encoder); 1832 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1833 nv_encoder->crtc = encoder->crtc;
1834
1819 switch (nv_encoder->dcb->type) { 1835 switch (nv_encoder->dcb->type) {
1820 case DCB_OUTPUT_TMDS: 1836 case DCB_OUTPUT_TMDS:
1821 if (nv_encoder->dcb->sorconf.link & 1) { 1837 if (nv_encoder->dcb->sorconf.link & 1) {
@@ -1827,7 +1843,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
1827 proto = 0x2; 1843 proto = 0x2;
1828 } 1844 }
1829 1845
1830 nv50_hdmi_mode_set(encoder, mode); 1846 nv50_hdmi_mode_set(&nv_encoder->base.base, mode);
1831 break; 1847 break;
1832 case DCB_OUTPUT_LVDS: 1848 case DCB_OUTPUT_LVDS:
1833 proto = 0x0; 1849 proto = 0x0;
@@ -1883,19 +1899,11 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
1883 break; 1899 break;
1884 } 1900 }
1885 1901
1886 nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); 1902 nv50_sor_dpms(&nv_encoder->base.base, DRM_MODE_DPMS_ON);
1887 1903
1888 push = evo_wait(nv50_mast(dev), 8); 1904 if (nv50_vers(mast) >= NVD0_DISP_CLASS) {
1889 if (push) { 1905 u32 *push = evo_wait(mast, 3);
1890 if (nv50_vers(mast) < NVD0_DISP_CLASS) { 1906 if (push) {
1891 u32 ctrl = (depth << 16) | (proto << 8) | owner;
1892 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1893 ctrl |= 0x00001000;
1894 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1895 ctrl |= 0x00002000;
1896 evo_mthd(push, 0x0600 + (nv_encoder->or * 0x040), 1);
1897 evo_data(push, ctrl);
1898 } else {
1899 u32 magic = 0x31ec6000 | (nv_crtc->index << 25); 1907 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
1900 u32 syncs = 0x00000001; 1908 u32 syncs = 0x00000001;
1901 1909
@@ -1910,14 +1918,21 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
1910 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2); 1918 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
1911 evo_data(push, syncs | (depth << 6)); 1919 evo_data(push, syncs | (depth << 6));
1912 evo_data(push, magic); 1920 evo_data(push, magic);
1913 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 1); 1921 evo_kick(push, mast);
1914 evo_data(push, owner | (proto << 8));
1915 } 1922 }
1916 1923
1917 evo_kick(push, mast); 1924 ctrl = proto << 8;
1925 mask = 0x00000f00;
1926 } else {
1927 ctrl = (depth << 16) | (proto << 8);
1928 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1929 ctrl |= 0x00001000;
1930 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1931 ctrl |= 0x00002000;
1932 mask = 0x000f3f00;
1918 } 1933 }
1919 1934
1920 nv_encoder->crtc = encoder->crtc; 1935 nv50_sor_ctrl(nv_encoder, mask | owner, ctrl | owner);
1921} 1936}
1922 1937
1923static void 1938static void