diff options
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 | |||
125 | nouveau-y += core/subdev/gpio/base.o | 125 | nouveau-y += core/subdev/gpio/base.o |
126 | nouveau-y += core/subdev/gpio/nv10.o | 126 | nouveau-y += core/subdev/gpio/nv10.o |
127 | nouveau-y += core/subdev/gpio/nv50.o | 127 | nouveau-y += core/subdev/gpio/nv50.o |
128 | nouveau-y += core/subdev/gpio/nv92.o | ||
128 | nouveau-y += core/subdev/gpio/nvd0.o | 129 | nouveau-y += core/subdev/gpio/nvd0.o |
129 | nouveau-y += core/subdev/gpio/nve0.o | 130 | nouveau-y += core/subdev/gpio/nve0.o |
130 | nouveau-y += core/subdev/i2c/base.o | 131 | nouveau-y += core/subdev/i2c/base.o |
131 | nouveau-y += core/subdev/i2c/anx9805.o | 132 | nouveau-y += core/subdev/i2c/anx9805.o |
132 | nouveau-y += core/subdev/i2c/aux.o | 133 | nouveau-y += core/subdev/i2c/aux.o |
133 | nouveau-y += core/subdev/i2c/bit.o | 134 | nouveau-y += core/subdev/i2c/bit.o |
135 | nouveau-y += core/subdev/i2c/pad.o | ||
136 | nouveau-y += core/subdev/i2c/padnv04.o | ||
137 | nouveau-y += core/subdev/i2c/padnv94.o | ||
134 | nouveau-y += core/subdev/i2c/nv04.o | 138 | nouveau-y += core/subdev/i2c/nv04.o |
135 | nouveau-y += core/subdev/i2c/nv4e.o | 139 | nouveau-y += core/subdev/i2c/nv4e.o |
136 | nouveau-y += core/subdev/i2c/nv50.o | 140 | nouveau-y += core/subdev/i2c/nv50.o |
137 | nouveau-y += core/subdev/i2c/nv94.o | 141 | nouveau-y += core/subdev/i2c/nv94.o |
138 | nouveau-y += core/subdev/i2c/nvd0.o | 142 | nouveau-y += core/subdev/i2c/nvd0.o |
143 | nouveau-y += core/subdev/i2c/nve0.o | ||
139 | nouveau-y += core/subdev/ibus/nvc0.o | 144 | nouveau-y += core/subdev/ibus/nvc0.o |
140 | nouveau-y += core/subdev/ibus/nve0.o | 145 | nouveau-y += core/subdev/ibus/nve0.o |
141 | nouveau-y += core/subdev/ibus/gk20a.o | 146 | nouveau-y += core/subdev/ibus/gk20a.o |
@@ -217,6 +222,9 @@ nouveau-y += core/engine/device/nvc0.o | |||
217 | nouveau-y += core/engine/device/nve0.o | 222 | nouveau-y += core/engine/device/nve0.o |
218 | nouveau-y += core/engine/device/gm100.o | 223 | nouveau-y += core/engine/device/gm100.o |
219 | nouveau-y += core/engine/disp/base.o | 224 | nouveau-y += core/engine/disp/base.o |
225 | nouveau-y += core/engine/disp/conn.o | ||
226 | nouveau-y += core/engine/disp/outp.o | ||
227 | nouveau-y += core/engine/disp/outpdp.o | ||
220 | nouveau-y += core/engine/disp/nv04.o | 228 | nouveau-y += core/engine/disp/nv04.o |
221 | nouveau-y += core/engine/disp/nv50.o | 229 | nouveau-y += core/engine/disp/nv50.o |
222 | nouveau-y += core/engine/disp/nv84.o | 230 | nouveau-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 | ||
41 | void | 47 | void |
@@ -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 | ||
56 | static void | 68 | static void |
@@ -65,38 +77,47 @@ nouveau_event_fini(struct nouveau_eventh *handler) | |||
65 | } | 77 | } |
66 | 78 | ||
67 | static int | 79 | static int |
68 | nouveau_event_init(struct nouveau_event *event, int index, | 80 | nouveau_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 | ||
89 | int | 104 | int |
90 | nouveau_event_new(struct nouveau_event *event, int index, | 105 | nouveau_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 | ||
118 | void | 139 | void |
119 | nouveau_event_trigger(struct nouveau_event *event, int index) | 140 | nouveau_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 | ||
146 | int | 172 | int |
147 | nouveau_event_create(int index_nr, struct nouveau_event **pevent) | 173 | nouveau_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 | |||
29 | static int | ||
30 | nouveau_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 | |||
44 | int | ||
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 | |||
59 | fail_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 | |||
67 | int | ||
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 | |||
86 | fail_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 | ||
27 | void | 94 | void |
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 | |||
30 | static void | ||
31 | nvkm_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 | |||
43 | static int | ||
44 | nvkm_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 | |||
52 | int | ||
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 | |||
61 | int | ||
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 | |||
73 | void | ||
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 | |||
81 | int | ||
82 | nvkm_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 | |||
139 | done: | ||
140 | INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | int | ||
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 | |||
161 | struct nouveau_oclass * | ||
162 | nvkm_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 | |||
6 | struct 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 | |||
34 | int nvkm_connector_create_(struct nouveau_object *, struct nouveau_object *, | ||
35 | struct nouveau_oclass *, struct nvbios_connE *, | ||
36 | int, int, void **); | ||
37 | |||
38 | int _nvkm_connector_ctor(struct nouveau_object *, struct nouveau_object *, | ||
39 | struct nouveau_oclass *, void *, u32, | ||
40 | struct nouveau_object **); | ||
41 | void _nvkm_connector_dtor(struct nouveau_object *); | ||
42 | int _nvkm_connector_init(struct nouveau_object *); | ||
43 | int _nvkm_connector_fini(struct nouveau_object *, bool); | ||
44 | |||
45 | struct 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 | *****************************************************************************/ |
43 | struct dp_state { | 41 | struct 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 | ||
58 | static int | 52 | static int |
59 | dp_set_link_config(struct dp_state *dp) | 53 | dp_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 | ||
110 | static void | 108 | static void |
111 | dp_set_training_pattern(struct dp_state *dp, u8 pattern) | 109 | dp_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 | ||
124 | static int | 124 | static int |
125 | dp_link_train_commit(struct dp_state *dp) | 125 | dp_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 | ||
147 | static int | 170 | static int |
148 | dp_link_train_update(struct dp_state *dp, u32 delay) | 171 | dp_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) | |||
199 | static int | 231 | static int |
200 | dp_link_train_eq(struct dp_state *dp) | 232 | dp_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) | |||
231 | static void | 264 | static void |
232 | dp_link_train_init(struct dp_state *dp, bool spread) | 265 | dp_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 | ||
254 | static void | 290 | static void |
255 | dp_link_train_fini(struct dp_state *dp) | 291 | dp_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 | ||
270 | int | 309 | static const struct dp_rates { |
271 | nouveau_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 | |||
326 | void | ||
327 | nouveau_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 | ||
59 | struct nouveau_disp; | 73 | void nouveau_dp_train(struct work_struct *); |
60 | struct dcb_output; | ||
61 | |||
62 | struct 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 | |||
71 | extern const struct nouveau_dp_func nv94_sor_dp_func; | ||
72 | extern const struct nouveau_dp_func nvd0_sor_dp_func; | ||
73 | extern const struct nouveau_dp_func nv50_pior_dp_func; | ||
74 | |||
75 | int 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 | ||
88 | static void | 88 | static void |
89 | nv04_disp_vblank_enable(struct nouveau_event *event, int head) | 89 | nv04_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 | ||
94 | static void | 94 | static void |
95 | nv04_disp_vblank_disable(struct nouveau_event *event, int head) | 95 | nv04_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 | ||
831 | static void | 831 | static void |
832 | nv50_disp_base_vblank_enable(struct nouveau_event *event, int head) | 832 | nv50_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 | ||
837 | static void | 837 | static void |
838 | nv50_disp_base_vblank_disable(struct nouveau_event *event, int head) | 838 | nv50_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 | ||
1117 | static u16 | 1117 | static struct nvkm_output * |
1118 | exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, | 1118 | exec_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 | ||
1169 | static bool | 1174 | static struct nvkm_output * |
1170 | exec_script(struct nv50_disp_priv *priv, int head, int id) | 1175 | exec_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 | ||
1227 | static u32 | 1231 | static struct nvkm_output * |
1228 | exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, | 1232 | exec_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 | ||
1316 | static void | 1319 | static void |
@@ -1322,7 +1325,35 @@ nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head) | |||
1322 | static void | 1325 | static void |
1323 | nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) | 1326 | nv50_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 | ||
1328 | static void | 1359 | static void |
@@ -1444,56 +1475,83 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, | |||
1444 | static void | 1475 | static void |
1445 | nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) | 1476 | nv50_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 | |||
1521 | static void | 1579 | static void |
1522 | nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head) | 1580 | nv50_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 | ||
1550 | void | 1594 | void |
@@ -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 | ||
1663 | struct nouveau_oclass * | 1706 | struct nouveau_oclass * |
1707 | nv50_disp_outp_sclass[] = { | ||
1708 | &nv50_pior_dp_impl.base.base, | ||
1709 | NULL | ||
1710 | }; | ||
1711 | |||
1712 | struct nouveau_oclass * | ||
1664 | nv50_disp_oclass = &(struct nv50_disp_impl) { | 1713 | nv50_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 | ||
15 | struct nv50_disp_impl { | 17 | struct 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 *); | |||
199 | extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan; | 199 | extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan; |
200 | extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan; | 200 | extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan; |
201 | 201 | ||
202 | extern struct nvkm_output_dp_impl nv50_pior_dp_impl; | ||
203 | extern struct nouveau_oclass *nv50_disp_outp_sclass[]; | ||
204 | |||
205 | extern struct nvkm_output_dp_impl nv94_sor_dp_impl; | ||
206 | int nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); | ||
207 | extern struct nouveau_oclass *nv94_disp_outp_sclass[]; | ||
208 | |||
209 | extern struct nvkm_output_dp_impl nvd0_sor_dp_impl; | ||
210 | extern 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 | ||
131 | struct nouveau_oclass * | 130 | struct nouveau_oclass * |
131 | nv94_disp_outp_sclass[] = { | ||
132 | &nv50_pior_dp_impl.base.base, | ||
133 | &nv94_sor_dp_impl.base.base, | ||
134 | NULL | ||
135 | }; | ||
136 | |||
137 | struct nouveau_oclass * | ||
132 | nv94_disp_oclass = &(struct nv50_disp_impl) { | 138 | nv94_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 | ||
750 | static void | 750 | static void |
751 | nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head) | 751 | nvd0_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 | ||
756 | static void | 756 | static void |
757 | nvd0_disp_base_vblank_disable(struct nouveau_event *event, int head) | 757 | nvd0_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 | ||
918 | static u16 | 919 | static struct nvkm_output * |
919 | exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, | 920 | exec_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 | ||
956 | static bool | 965 | static struct nvkm_output * |
957 | exec_script(struct nv50_disp_priv *priv, int head, int id) | 966 | exec_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 | ||
993 | static u32 | 1001 | static struct nvkm_output * |
994 | exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, | 1002 | exec_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 | ||
1056 | static void | 1063 | static void |
@@ -1062,7 +1069,23 @@ nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head) | |||
1062 | static void | 1069 | static void |
1063 | nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head) | 1070 | nvd0_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 | ||
1068 | static void | 1091 | static void |
@@ -1124,49 +1147,52 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, | |||
1124 | static void | 1147 | static void |
1125 | nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) | 1148 | nvd0_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 | ||
1164 | static void | 1189 | static void |
1165 | nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head) | 1190 | nvd0_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 | ||
1172 | void | 1198 | void |
@@ -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 | ||
1359 | struct nouveau_oclass * | 1384 | struct nouveau_oclass * |
1385 | nvd0_disp_outp_sclass[] = { | ||
1386 | &nvd0_sor_dp_impl.base.base, | ||
1387 | NULL | ||
1388 | }; | ||
1389 | |||
1390 | struct nouveau_oclass * | ||
1360 | nvd0_disp_oclass = &(struct nv50_disp_impl) { | 1391 | nvd0_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 | |||
31 | int | ||
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 | |||
39 | int | ||
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 | |||
49 | void | ||
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 | |||
58 | int | ||
59 | nvkm_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 | |||
109 | int | ||
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 | |||
126 | struct nouveau_oclass * | ||
127 | nvkm_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 | |||
6 | struct 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 | |||
34 | int nvkm_output_create_(struct nouveau_object *, struct nouveau_object *, | ||
35 | struct nouveau_oclass *, struct dcb_output *, | ||
36 | int, int, void **); | ||
37 | |||
38 | int _nvkm_output_ctor(struct nouveau_object *, struct nouveau_object *, | ||
39 | struct nouveau_oclass *, void *, u32, | ||
40 | struct nouveau_object **); | ||
41 | void _nvkm_output_dtor(struct nouveau_object *); | ||
42 | int _nvkm_output_init(struct nouveau_object *); | ||
43 | int _nvkm_output_fini(struct nouveau_object *, bool); | ||
44 | |||
45 | struct 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 | |||
31 | int | ||
32 | nvkm_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 | |||
75 | done: | ||
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 | |||
100 | static void | ||
101 | nvkm_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 | |||
121 | static void | ||
122 | nvkm_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 | |||
134 | static void | ||
135 | nvkm_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 | |||
159 | static int | ||
160 | nvkm_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 | |||
169 | int | ||
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 | |||
178 | int | ||
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 | |||
186 | void | ||
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 | |||
194 | int | ||
195 | nvkm_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 | |||
261 | int | ||
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 | |||
9 | struct 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 | |||
44 | int nvkm_output_dp_create_(struct nouveau_object *, struct nouveau_object *, | ||
45 | struct nouveau_oclass *, struct dcb_output *, | ||
46 | int, int, void **); | ||
47 | |||
48 | int _nvkm_output_dp_ctor(struct nouveau_object *, struct nouveau_object *, | ||
49 | struct nouveau_oclass *, void *, u32, | ||
50 | struct nouveau_object **); | ||
51 | void _nvkm_output_dp_dtor(struct nouveau_object *); | ||
52 | int _nvkm_output_dp_init(struct nouveau_object *); | ||
53 | int _nvkm_output_dp_fini(struct nouveau_object *, bool); | ||
54 | |||
55 | struct 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 | |||
63 | int 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 | *****************************************************************************/ |
38 | static struct nouveau_i2c_port * | 38 | |
39 | nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp) | 39 | static int |
40 | nv50_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 | ||
58 | struct nvkm_output_impl | ||
59 | nv50_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 | |||
45 | static int | 73 | static int |
46 | nv50_pior_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, | 74 | nv50_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 | ||
63 | static int | 82 | static int |
64 | nv50_pior_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, | 83 | nv50_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); | 88 | static int |
89 | nv50_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; | 97 | static int |
98 | nv50_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 | ||
77 | static int | 106 | static int |
78 | nv50_pior_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, | 107 | nv50_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 | ||
95 | const struct nouveau_dp_func | 126 | struct nvkm_output_dp_impl |
96 | nv50_pior_dp_func = { | 127 | nv50_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 | |||
105 | int | 145 | int |
106 | nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data) | 146 | nv50_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 | ||
6 | struct nouveau_disp_impl { | 10 | struct 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 | |||
32 | int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *, | ||
33 | struct nouveau_oclass *, int heads, | ||
34 | const char *, const char *, int, void **); | ||
35 | void _nouveau_disp_dtor(struct nouveau_object *); | ||
36 | int _nouveau_disp_init(struct nouveau_object *); | ||
37 | int _nouveau_disp_fini(struct nouveau_object *, bool); | ||
38 | |||
39 | extern struct nouveau_oclass *nvkm_output_oclass; | ||
40 | extern 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 | |||
47 | nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) | 47 | nv50_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 | ||
35 | static inline u32 | 37 | static inline u32 |
36 | nv94_sor_soff(struct dcb_output *outp) | 38 | nv94_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 | ||
41 | static inline u32 | 43 | static inline u32 |
42 | nv94_sor_loff(struct dcb_output *outp) | 44 | nv94_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 | ||
47 | static inline u32 | 49 | static inline u32 |
@@ -55,77 +57,96 @@ nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) | |||
55 | } | 57 | } |
56 | 58 | ||
57 | static int | 59 | static int |
58 | nv94_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, | 60 | nv94_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 | ||
68 | int | ||
69 | nv94_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 | |||
67 | static int | 85 | static int |
68 | nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, | 86 | nv94_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 | ||
94 | static int | 105 | static int |
95 | nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, | 106 | nv94_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 | ||
126 | const struct nouveau_dp_func | 139 | struct nvkm_output_dp_impl |
127 | nv94_sor_dp_func = { | 140 | nv94_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 | ||
35 | static inline u32 | 36 | static inline u32 |
36 | nvd0_sor_soff(struct dcb_output *outp) | 37 | nvd0_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 | ||
41 | static inline u32 | 42 | static inline u32 |
42 | nvd0_sor_loff(struct dcb_output *outp) | 43 | nvd0_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 | ||
47 | static inline u32 | 48 | static inline u32 |
@@ -52,77 +53,80 @@ nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) | |||
52 | } | 53 | } |
53 | 54 | ||
54 | static int | 55 | static int |
55 | nvd0_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, | 56 | nvd0_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 | ||
64 | static int | 64 | static int |
65 | nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, | 65 | nvd0_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 | ||
90 | static int | 83 | static int |
91 | nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, | 84 | nvd0_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 | ||
123 | const struct nouveau_dp_func | 119 | struct nvkm_output_dp_impl |
124 | nvd0_sor_dp_func = { | 120 | nvd0_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 | ||
391 | static void | 391 | static void |
392 | nv84_fifo_uevent_enable(struct nouveau_event *event, int index) | 392 | nv84_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 | ||
398 | static void | 398 | static void |
399 | nv84_fifo_uevent_disable(struct nouveau_event *event, int index) | 399 | nv84_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 | ||
829 | static void | 829 | static void |
830 | nvc0_fifo_uevent_enable(struct nouveau_event *event, int index) | 830 | nvc0_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 | ||
836 | static void | 836 | static void |
837 | nvc0_fifo_uevent_disable(struct nouveau_event *event, int index) | 837 | nvc0_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) | |||
859 | static void | 859 | static void |
860 | nve0_fifo_intr_engine(struct nve0_fifo_priv *priv) | 860 | nve0_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 | ||
865 | static void | 865 | static void |
@@ -952,14 +952,14 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) | |||
952 | } | 952 | } |
953 | 953 | ||
954 | static void | 954 | static void |
955 | nve0_fifo_uevent_enable(struct nouveau_event *event, int index) | 955 | nve0_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 | ||
961 | static void | 961 | static void |
962 | nve0_fifo_uevent_disable(struct nouveau_event *event, int index) | 962 | nve0_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 | ||
126 | static int | 126 | static int |
127 | nv50_software_vblsem_release(void *data, int head) | 127 | nv50_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 | ||
20 | struct nv50_software_cclass { | 20 | struct 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 | ||
25 | struct nv50_software_chan { | 25 | struct 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 | ||
106 | static int | 106 | static int |
107 | nvc0_software_vblsem_release(void *data, int head) | 107 | nvc0_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 | ||
20 | struct nouveau_event { | 21 | struct 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 | ||
35 | int nouveau_event_create(int index_nr, struct nouveau_event **); | 36 | int nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **); |
36 | void nouveau_event_destroy(struct nouveau_event **); | 37 | void nouveau_event_destroy(struct nouveau_event **); |
37 | void nouveau_event_trigger(struct nouveau_event *, int index); | 38 | void nouveau_event_trigger(struct nouveau_event *, u32 types, int index); |
38 | 39 | ||
39 | int nouveau_event_new(struct nouveau_event *, int index, | 40 | int 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 **); |
42 | void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **); | 43 | void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **); |
43 | void nouveau_event_get(struct nouveau_eventh *); | 44 | void 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 | ||
9 | enum 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 | |||
9 | struct nouveau_disp { | 16 | struct 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 | |||
32 | int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *, | ||
33 | struct nouveau_oclass *, int heads, | ||
34 | const char *, const char *, int, void **); | ||
35 | void _nouveau_disp_dtor(struct nouveau_object *); | ||
36 | #define _nouveau_disp_init _nouveau_engine_init | ||
37 | #define _nouveau_disp_fini _nouveau_engine_fini | ||
38 | |||
39 | extern struct nouveau_oclass *nv04_disp_oclass; | 31 | extern struct nouveau_oclass *nv04_disp_oclass; |
40 | extern struct nouveau_oclass *nv50_disp_oclass; | 32 | extern struct nouveau_oclass *nv50_disp_oclass; |
41 | extern struct nouveau_oclass *nv84_disp_oclass; | 33 | extern 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 | ||
25 | u16 dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); | 25 | struct nvbios_connT { |
26 | u16 dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len); | 26 | }; |
27 | |||
28 | u32 nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); | ||
29 | u32 nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, | ||
30 | struct nvbios_connT *info); | ||
31 | |||
32 | struct 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 | |||
42 | u32 nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr); | ||
43 | u32 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 | ||
19 | struct nvbios_dpcfg { | 19 | struct 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 | ||
25 | u16 | 26 | u16 |
@@ -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 *); |
29 | u16 | 30 | u16 |
30 | nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 un, u8 vs, u8 pe, | 31 | nvbios_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 | ||
11 | enum 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 | |||
11 | struct nouveau_gpio { | 17 | struct 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) \ | 35 | extern struct nouveau_oclass *nv10_gpio_oclass; |
35 | nouveau_gpio_create_((p), (e), (o), (l), sizeof(**d), (void **)d) | 36 | extern struct nouveau_oclass *nv50_gpio_oclass; |
36 | #define nouveau_gpio_destroy(p) ({ \ | 37 | extern struct nouveau_oclass *nv92_gpio_oclass; |
37 | struct nouveau_gpio *gpio = (p); \ | 38 | extern struct nouveau_oclass *nvd0_gpio_oclass; |
38 | _nouveau_gpio_dtor(nv_object(gpio)); \ | 39 | extern struct nouveau_oclass *nve0_gpio_oclass; |
39 | }) | ||
40 | #define nouveau_gpio_fini(p,s) \ | ||
41 | nouveau_subdev_fini(&(p)->base, (s)) | ||
42 | |||
43 | int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, | ||
44 | struct nouveau_oclass *, int, int, void **); | ||
45 | void _nouveau_gpio_dtor(struct nouveau_object *); | ||
46 | int nouveau_gpio_init(struct nouveau_gpio *); | ||
47 | |||
48 | extern struct nouveau_oclass nv10_gpio_oclass; | ||
49 | extern struct nouveau_oclass nv50_gpio_oclass; | ||
50 | extern struct nouveau_oclass nvd0_gpio_oclass; | ||
51 | extern 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 | ||
17 | enum 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 | |||
17 | struct nouveau_i2c_port { | 28 | struct 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 | ||
27 | struct nouveau_i2c_func { | 40 | struct 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 | |||
54 | int 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 **); | ||
59 | void _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 | |||
63 | struct nouveau_i2c_board_info { | 52 | struct 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 | ||
68 | struct nouveau_i2c { | 57 | struct 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) \ | 82 | extern struct nouveau_oclass *nv04_i2c_oclass; |
87 | nouveau_i2c_create_((p), (e), (o), (s), sizeof(**d), (void **)d) | 83 | extern struct nouveau_oclass *nv4e_i2c_oclass; |
88 | #define nouveau_i2c_destroy(p) ({ \ | 84 | extern struct nouveau_oclass *nv50_i2c_oclass; |
89 | struct nouveau_i2c *i2c = (p); \ | 85 | extern struct nouveau_oclass *nv94_i2c_oclass; |
90 | _nouveau_i2c_dtor(nv_object(i2c)); \ | 86 | extern struct nouveau_oclass *nvd0_i2c_oclass; |
91 | }) | 87 | extern 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 | |||
101 | int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *, | ||
102 | struct nouveau_oclass *, struct nouveau_oclass *, | ||
103 | int, void **); | ||
104 | void _nouveau_i2c_dtor(struct nouveau_object *); | ||
105 | int _nouveau_i2c_init(struct nouveau_object *); | ||
106 | int _nouveau_i2c_fini(struct nouveau_object *, bool); | ||
107 | |||
108 | extern struct nouveau_oclass nv04_i2c_oclass; | ||
109 | extern struct nouveau_oclass nv4e_i2c_oclass; | ||
110 | extern struct nouveau_oclass nv50_i2c_oclass; | ||
111 | extern struct nouveau_oclass nv94_i2c_oclass; | ||
112 | extern struct nouveau_oclass nvd0_i2c_oclass; | ||
113 | extern struct nouveau_oclass nouveau_anx9805_sclass[]; | ||
114 | |||
115 | extern const struct i2c_algorithm nouveau_i2c_bit_algo; | ||
116 | extern const struct i2c_algorithm nouveau_i2c_aux_algo; | ||
117 | 88 | ||
118 | static inline int | 89 | static inline int |
119 | nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg) | 90 | nv_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 | ||
31 | u16 | 31 | u32 |
32 | dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) | 32 | nvbios_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 | ||
48 | u16 | 48 | u32 |
49 | dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) | 49 | nvbios_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 | |||
64 | u32 | ||
65 | nvbios_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 | |||
74 | u32 | ||
75 | nvbios_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 | ||
186 | u16 | 188 | u16 |
187 | nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe, | 189 | nvbios_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 | |||
98 | init_conn(struct nvbios_init *init) | 98 | init_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 | |||
29 | static int | 30 | static int |
30 | nouveau_gpio_drive(struct nouveau_gpio *gpio, | 31 | nouveau_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 | ||
36 | static int | 38 | static int |
37 | nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line) | 39 | nouveau_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 | ||
42 | static int | 45 | static 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 | ||
108 | static void | ||
109 | nouveau_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 | |||
116 | static void | ||
117 | nouveau_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 | |||
124 | static void | ||
125 | nouveau_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 | |||
142 | int | ||
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 | |||
155 | static 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 | |||
166 | int | ||
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 | |||
105 | void | 182 | void |
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) | |||
113 | int | 190 | int |
114 | nouveau_gpio_create_(struct nouveau_object *parent, | 191 | nouveau_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 | ||
138 | static 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 | |||
149 | int | 222 | int |
150 | nouveau_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 | ||
29 | struct nv10_gpio_priv { | ||
30 | struct nouveau_gpio base; | ||
31 | }; | ||
32 | |||
33 | static int | 29 | static int |
34 | nv10_gpio_sense(struct nouveau_gpio *gpio, int line) | 30 | nv10_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 | ||
85 | static void | 81 | static void |
86 | nv10_gpio_intr(struct nouveau_subdev *subdev) | 82 | nv10_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 | |||
102 | static void | ||
103 | nv10_gpio_intr_enable(struct nouveau_event *event, int line) | ||
104 | { | ||
105 | nv_wr32(event->priv, 0x001104, 0x00010001 << line); | ||
106 | nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00010001 << line); | ||
107 | } | ||
108 | |||
109 | static void | ||
110 | nv10_gpio_intr_disable(struct nouveau_event *event, int line) | ||
111 | { | ||
112 | nv_wr32(event->priv, 0x001104, 0x00010001 << line); | ||
113 | nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00000000); | ||
114 | } | ||
115 | |||
116 | static int | ||
117 | nv10_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 | ||
138 | static void | 91 | static void |
139 | nv10_gpio_dtor(struct nouveau_object *object) | 92 | nv10_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 | |||
145 | static int | ||
146 | nv10_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 | |||
160 | static int | ||
161 | nv10_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 | ||
168 | struct nouveau_oclass | 102 | struct nouveau_oclass * |
169 | nv10_gpio_oclass = { | 103 | nv10_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 | ||
27 | struct nv50_gpio_priv { | 27 | void |
28 | struct nouveau_gpio base; | ||
29 | }; | ||
30 | |||
31 | static void | ||
32 | nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) | 28 | nv50_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 | ||
75 | static int | 70 | int |
76 | nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) | 71 | nv50_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 | ||
87 | static int | 82 | int |
88 | nv50_gpio_sense(struct nouveau_gpio *gpio, int line) | 83 | nv50_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 | ||
98 | void | 93 | static void |
99 | nv50_gpio_intr(struct nouveau_subdev *subdev) | 94 | nv50_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 | |||
123 | void | ||
124 | nv50_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 | |||
132 | void | ||
133 | nv50_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 | |||
141 | static int | ||
142 | nv50_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 | |||
166 | void | ||
167 | nv50_gpio_dtor(struct nouveau_object *object) | ||
168 | { | ||
169 | struct nv50_gpio_priv *priv = (void *)object; | ||
170 | nouveau_gpio_destroy(&priv->base); | ||
171 | } | ||
172 | |||
173 | int | ||
174 | nv50_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 | ||
194 | int | 103 | static void |
195 | nv50_gpio_fini(struct nouveau_object *object, bool suspend) | 104 | nv50_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 | ||
204 | struct nouveau_oclass | 114 | struct nouveau_oclass * |
205 | nv50_gpio_oclass = { | 115 | nv50_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 | |||
27 | void | ||
28 | nv92_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 | |||
40 | void | ||
41 | nv92_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 | |||
59 | struct nouveau_oclass * | ||
60 | nv92_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 | ||
27 | struct nvd0_gpio_priv { | ||
28 | struct nouveau_gpio base; | ||
29 | }; | ||
30 | |||
31 | void | 27 | void |
32 | nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match) | 28 | nvd0_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 | ||
75 | static int | 70 | struct nouveau_oclass * |
76 | nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 71 | nvd0_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 | |||
98 | struct nouveau_oclass | ||
99 | nvd0_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 | ||
27 | struct nve0_gpio_priv { | 27 | static void |
28 | struct nouveau_gpio base; | 28 | nve0_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) |
29 | }; | ||
30 | |||
31 | void | ||
32 | nve0_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 | ||
50 | void | 40 | void |
51 | nve0_gpio_intr_enable(struct nouveau_event *event, int line) | 41 | nve0_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); | |
59 | void | 49 | mask >>= 16; |
60 | nve0_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 | |||
68 | int | ||
69 | nve0_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 | |||
77 | int | ||
78 | nve0_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 | |||
92 | void | ||
93 | nve0_gpio_dtor(struct nouveau_object *object) | ||
94 | { | ||
95 | struct nve0_gpio_priv *priv = (void *)object; | ||
96 | nouveau_gpio_destroy(&priv->base); | ||
97 | } | ||
98 | |||
99 | static int | ||
100 | nve0_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 | ||
122 | struct nouveau_oclass | 59 | struct nouveau_oclass * |
123 | nve0_gpio_oclass = { | 60 | nve0_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 | ||
6 | void nv50_gpio_dtor(struct nouveau_object *); | 6 | #define nouveau_gpio_create(p,e,o,d) \ |
7 | int nv50_gpio_init(struct nouveau_object *); | 7 | nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d) |
8 | int nv50_gpio_fini(struct nouveau_object *, bool); | 8 | #define nouveau_gpio_destroy(p) ({ \ |
9 | void nv50_gpio_intr(struct nouveau_subdev *); | 9 | struct nouveau_gpio *gpio = (p); \ |
10 | void nv50_gpio_intr_enable(struct nouveau_event *, int line); | 10 | _nouveau_gpio_dtor(nv_object(gpio)); \ |
11 | void 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 | |||
21 | int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, | ||
22 | struct nouveau_oclass *, int, void **); | ||
23 | int _nouveau_gpio_ctor(struct nouveau_object *, struct nouveau_object *, | ||
24 | struct nouveau_oclass *, void *, u32, | ||
25 | struct nouveau_object **); | ||
26 | void _nouveau_gpio_dtor(struct nouveau_object *); | ||
27 | int _nouveau_gpio_init(struct nouveau_object *); | ||
28 | int _nouveau_gpio_fini(struct nouveau_object *, bool); | ||
29 | |||
30 | struct 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 | |||
55 | void nv50_gpio_reset(struct nouveau_gpio *, u8); | ||
56 | int nv50_gpio_drive(struct nouveau_gpio *, int, int, int); | ||
57 | int nv50_gpio_sense(struct nouveau_gpio *, int); | ||
58 | |||
59 | void nv92_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *); | ||
60 | void nv92_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32); | ||
12 | 61 | ||
13 | void nvd0_gpio_reset(struct nouveau_gpio *, u8); | 62 | void nvd0_gpio_reset(struct nouveau_gpio *, u8); |
14 | int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int); | 63 | int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int); |
15 | int nvd0_gpio_sense(struct nouveau_gpio *, int); | 64 | int 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 | ||
27 | struct anx9805_i2c_port { | 27 | struct 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 | ||
62 | static int | 64 | static int |
63 | anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size) | 65 | anx9805_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; |
99 | done: | 114 | done: |
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 | ||
27 | int | 27 | int |
28 | nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) | 28 | nv_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) | |||
38 | int | 42 | int |
39 | nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) | 43 | nv_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 | |||
50 | aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | 58 | aux_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 | |
54 | static void | ||
55 | nouveau_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 | ||
53 | static void | 62 | static 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 | ||
94 | int | ||
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 | |||
85 | void | 103 | void |
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 | ||
215 | static void | ||
216 | nouveau_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 | |||
227 | static int | ||
228 | nouveau_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 | |||
248 | static int | ||
249 | nouveau_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 | |||
265 | static void | ||
266 | nouveau_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 | |||
273 | static int | ||
274 | nouveau_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 | |||
196 | static int | 284 | static int |
197 | nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, | 285 | nouveau_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 | ||
328 | static void | ||
329 | nouveau_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 | |||
338 | static void | ||
339 | nouveau_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 | |||
348 | static void | ||
349 | nouveau_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 | |||
240 | int | 374 | int |
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); |
254 | fail: | 395 | fail: |
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 | |||
306 | nouveau_i2c_create_(struct nouveau_object *parent, | 449 | nouveau_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 | |||
560 | int | ||
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 | |||
28 | struct nv04_i2c_priv { | 29 | struct 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 | ||
118 | static int | 119 | struct nouveau_oclass * |
119 | nv04_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 120 | nv04_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 | |||
134 | struct nouveau_oclass | ||
135 | nv04_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 | |||
28 | struct nv4e_i2c_priv { | 29 | struct 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 | ||
110 | static int | 111 | struct nouveau_oclass * |
111 | nv4e_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 112 | nv4e_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 | |||
126 | struct nouveau_oclass | ||
127 | nv4e_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 | ||
124 | static int | 124 | struct nouveau_oclass * |
125 | nv50_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 125 | nv50_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 | |||
140 | struct nouveau_oclass | ||
141 | nv50_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 | ||
6 | struct nv50_i2c_priv { | 6 | struct 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 | ||
27 | void | ||
28 | nv94_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 | |||
41 | void | ||
42 | nv94_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 | ||
71 | int | 101 | int |
72 | nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) | 102 | nv94_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 | ||
148 | out: | 183 | out: |
149 | auxch_fini(aux, ch); | 184 | auxch_fini(aux, ch); |
150 | return ret; | 185 | return ret < 0 ? ret : (stat & 0x000f0000) >> 16; |
151 | } | ||
152 | |||
153 | void | ||
154 | nv94_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 | |||
164 | void | ||
165 | nv94_i2c_release(struct nouveau_i2c_port *base) | ||
166 | { | ||
167 | } | 186 | } |
168 | 187 | ||
169 | static const struct nouveau_i2c_func | 188 | static const struct nouveau_i2c_func |
170 | nv94_i2c_func = { | 189 | nv94_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 | ||
207 | static const struct nouveau_i2c_func | 224 | static const struct nouveau_i2c_func |
208 | nv94_aux_func = { | 225 | nv94_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 | ||
260 | static int | 276 | struct nouveau_oclass * |
261 | nv94_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 277 | nv94_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 | |||
276 | struct nouveau_oclass | ||
277 | nv94_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 | ||
43 | static const struct nouveau_i2c_func | 43 | static const struct nouveau_i2c_func |
44 | nvd0_i2c_func = { | 44 | nvd0_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 | ||
78 | static struct nouveau_oclass | 76 | struct nouveau_oclass |
79 | nvd0_i2c_sclass[] = { | 77 | nvd0_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 | ||
99 | static int | 97 | struct nouveau_oclass * |
100 | nvd0_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 98 | nvd0_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 | |||
115 | struct nouveau_oclass | ||
116 | nvd0_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 | |||
27 | static void | ||
28 | nve0_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 | |||
41 | static void | ||
42 | nve0_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 | |||
57 | struct nouveau_oclass * | ||
58 | nve0_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 | |||
27 | int | ||
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 | |||
36 | int | ||
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 | |||
45 | int | ||
46 | nvkm_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 | |||
74 | int | ||
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 | |||
6 | struct 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 | |||
13 | static inline struct nvkm_i2c_pad * | ||
14 | nvkm_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 | |||
37 | int nvkm_i2c_pad_create_(struct nouveau_object *, struct nouveau_object *, | ||
38 | struct nouveau_oclass *, int index, int, void **); | ||
39 | |||
40 | int _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 | ||
44 | int _nvkm_i2c_pad_init(struct nouveau_object *); | ||
45 | int _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 | |||
27 | struct nouveau_oclass | ||
28 | nv04_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 | |||
27 | struct nv94_i2c_pad { | ||
28 | struct nvkm_i2c_pad base; | ||
29 | int addr; | ||
30 | }; | ||
31 | |||
32 | static int | ||
33 | nv94_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 | |||
41 | static int | ||
42 | nv94_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 | |||
61 | static int | ||
62 | nv94_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 | |||
78 | struct nouveau_oclass | ||
79 | nv94_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 | |||
6 | extern struct nouveau_oclass nv04_i2c_pad_oclass; | ||
7 | extern 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 | |||
21 | int 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 **); | ||
26 | void _nouveau_i2c_port_dtor(struct nouveau_object *); | ||
27 | #define _nouveau_i2c_port_init nouveau_object_init | ||
28 | int _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 | |||
45 | int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *, | ||
46 | struct nouveau_oclass *, int, void **); | ||
47 | int _nouveau_i2c_ctor(struct nouveau_object *, struct nouveau_object *, | ||
48 | struct nouveau_oclass *, void *, u32, | ||
49 | struct nouveau_object **); | ||
50 | void _nouveau_i2c_dtor(struct nouveau_object *); | ||
51 | int _nouveau_i2c_init(struct nouveau_object *); | ||
52 | int _nouveau_i2c_fini(struct nouveau_object *, bool); | ||
53 | |||
54 | extern struct nouveau_oclass nouveau_anx9805_sclass[]; | ||
55 | extern struct nouveau_oclass nvd0_i2c_sclass[]; | ||
56 | |||
57 | extern const struct i2c_algorithm nouveau_i2c_bit_algo; | ||
58 | extern const struct i2c_algorithm nouveau_i2c_aux_algo; | ||
59 | |||
60 | struct 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 | |||
82 | void nv94_aux_stat(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *); | ||
83 | void 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 | ||
48 | MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); | 49 | MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); |
49 | static int nouveau_tv_disable = 0; | 50 | static 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 | |||
100 | nouveau_connector_destroy(struct drm_connector *connector) | 102 | nouveau_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 | ||
110 | static struct nouveau_i2c_port * | 114 | static struct nouveau_encoder * |
111 | nouveau_connector_ddc_detect(struct drm_connector *connector, | 115 | nouveau_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 | ||
165 | static struct nouveau_encoder * | 167 | static 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 | ||
914 | static void | 908 | static void |
909 | nouveau_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 | |||
930 | static const struct drm_connector_funcs | ||
931 | nouveau_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 | |||
942 | static void | ||
915 | nouveau_connector_hotplug_work(struct work_struct *work) | 943 | nouveau_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 | ||
936 | static int | 967 | static int |
937 | nouveau_connector_hotplug(void *data, int index) | 968 | nouveau_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 | |||
976 | static ssize_t | ||
977 | nouveau_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 | ||
944 | static int | 1008 | static 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 | ||
38 | struct nouveau_i2c_port; | 38 | struct 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 | ||
75 | static inline struct nouveau_crtc *nouveau_crtc(struct drm_crtc *crtc) | 75 | static 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 | ||
80 | static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc) | 80 | static 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 | ||
44 | static int | 44 | static int |
45 | nouveau_display_vblank_handler(void *data, int head) | 45 | nouveau_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 | ||
58 | bool | 58 | int |
59 | nouveau_dp_detect(struct drm_encoder *encoder) | 59 | nouveau_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 */ |
87 | bool nouveau_dp_detect(struct drm_encoder *); | 88 | int nouveau_dp_detect(struct nouveau_encoder *); |
88 | void nouveau_dp_dpms(struct drm_encoder *, int mode, u32 datarate, | ||
89 | struct nouveau_object *); | ||
90 | 89 | ||
91 | struct nouveau_connector * | 90 | struct nouveau_connector * |
92 | nouveau_encoder_connector_get(struct nouveau_encoder *encoder); | 91 | nouveau_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 | ||
168 | static int | 168 | static int |
169 | nouveau_fence_wait_uevent_handler(void *data, int index) | 169 | nouveau_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 | |||
1207 | nv50_crtc_disable(struct drm_crtc *crtc) | 1208 | nv50_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 | ||
1702 | static void | 1704 | static void |
1703 | nv50_hdmi_disconnect(struct drm_encoder *encoder) | 1705 | nv50_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 | ||
1746 | static bool | 1757 | static bool |
@@ -1764,33 +1775,36 @@ nv50_sor_mode_fixup(struct drm_encoder *encoder, | |||
1764 | } | 1775 | } |
1765 | 1776 | ||
1766 | static void | 1777 | static void |
1767 | nv50_sor_disconnect(struct drm_encoder *encoder) | 1778 | nv50_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 | |||
1794 | static void | ||
1795 | nv50_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 | ||
1796 | static void | 1810 | static 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 | ||
1923 | static void | 1938 | static void |