diff options
author | Dave Airlie <airlied@redhat.com> | 2013-02-20 02:46:25 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-02-20 02:54:13 -0500 |
commit | 1f3a574a4bfe86ebf7d51fac37e0668397372fd8 (patch) | |
tree | 86308b3a63ea03151eff6e6b5c4ea96e2f509993 /drivers/gpu | |
parent | b81e059ec5a7128622ab5d74d78e9b4f361b54ae (diff) | |
parent | a91ed42de25e7e81159c0dd59faf8cac9dfa1d32 (diff) |
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next
Nothing terribly exciting in here probably:
- reworked thermal stuff from mupuf/I, has a chance of possibly working
well enough when we get to being able to reclock..
- driver will report mmio access faults on chipsets where it's supported
- will now sleep waiting on fences on nv84+ rather than polling
- some cleanup of the internal fencing, looking towards sli/dmabuf sync
- initial support for anx9805 dp/tmds encoder
- nv50+ display fixes related to the above, and also might fix a few
other issues
- nicer error reporting (will log process names with channel errors)
- various other random fixes
* 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: (87 commits)
nouveau: ACPI support depends on X86 and X86_PLATFORM_DEVICES
drm/nouveau/i2c: add support for ddc/aux, and dp link training on anx9805
drm/nv50: initial kms support for off-chip TMDS/DP encoders
drm/nv50-/disp: initial supervisor support for off-chip encoders
drm/nv50-/disp: initial work towards supporting external encoders
drm/nv50-/kms: remove unnecessary wait-for-completion points
drm/nv50-/disp: move DP link training to core and train from supervisor
drm/nv50-/disp: handle supervisor tasks from workqueue
drm/nouveau/i2c: create proper chipset-specific class implementations
drm/nv50-/disp: 0x0000 is a valid udisp config value
drm/nv50/devinit: reverse the logic for running encoder init scripts
drm/nouveau/bios: store a type/mask hash in parsed dcb data
drm/nouveau/i2c: extend type to 16-bits, add lookup-by-type function
drm/nouveau/i2c: aux channels not necessarily on nvio
drm/nouveau/i2c: fix a bit of a thinko in nv_wri2cr helper functions
drm/nouveau/bios: parse external transmitter type if off-chip
drm/nouveau: store i2c port pointer directly in nouveau_encoder
drm/nouveau/i2c: handle i2c/aux mux outside of port lookup function
drm/nv50/graph: avoid touching 400724, it doesn't exist
drm/nouveau: Fix DPMS 1 on G4 Snowball, from snow white to coal black.
...
Diffstat (limited to 'drivers/gpu')
148 files changed, 6923 insertions, 2740 deletions
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index 47ccc1ad5405..a7ff6d5a34b9 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig | |||
@@ -11,8 +11,9 @@ config DRM_NOUVEAU | |||
11 | select FRAMEBUFFER_CONSOLE if !EXPERT | 11 | select FRAMEBUFFER_CONSOLE if !EXPERT |
12 | select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT | 12 | select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT |
13 | select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT | 13 | select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT |
14 | select ACPI_WMI if ACPI | 14 | select X86_PLATFORM_DEVICES if ACPI && X86 |
15 | select MXM_WMI if ACPI | 15 | select ACPI_WMI if ACPI && X86 |
16 | select MXM_WMI if ACPI && X86 | ||
16 | select POWER_SUPPLY | 17 | select POWER_SUPPLY |
17 | help | 18 | help |
18 | Choose this option for open-source nVidia support. | 19 | Choose this option for open-source nVidia support. |
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index ab25752a0b1e..51d09729fc56 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile | |||
@@ -11,6 +11,7 @@ nouveau-y := core/core/client.o | |||
11 | nouveau-y += core/core/engctx.o | 11 | nouveau-y += core/core/engctx.o |
12 | nouveau-y += core/core/engine.o | 12 | nouveau-y += core/core/engine.o |
13 | nouveau-y += core/core/enum.o | 13 | nouveau-y += core/core/enum.o |
14 | nouveau-y += core/core/event.o | ||
14 | nouveau-y += core/core/falcon.o | 15 | nouveau-y += core/core/falcon.o |
15 | nouveau-y += core/core/gpuobj.o | 16 | nouveau-y += core/core/gpuobj.o |
16 | nouveau-y += core/core/handle.o | 17 | nouveau-y += core/core/handle.o |
@@ -40,6 +41,11 @@ nouveau-y += core/subdev/bios/mxm.o | |||
40 | nouveau-y += core/subdev/bios/perf.o | 41 | nouveau-y += core/subdev/bios/perf.o |
41 | nouveau-y += core/subdev/bios/pll.o | 42 | nouveau-y += core/subdev/bios/pll.o |
42 | nouveau-y += core/subdev/bios/therm.o | 43 | nouveau-y += core/subdev/bios/therm.o |
44 | nouveau-y += core/subdev/bios/xpio.o | ||
45 | nouveau-y += core/subdev/bus/nv04.o | ||
46 | nouveau-y += core/subdev/bus/nv31.o | ||
47 | nouveau-y += core/subdev/bus/nv50.o | ||
48 | nouveau-y += core/subdev/bus/nvc0.o | ||
43 | nouveau-y += core/subdev/clock/nv04.o | 49 | nouveau-y += core/subdev/clock/nv04.o |
44 | nouveau-y += core/subdev/clock/nv40.o | 50 | nouveau-y += core/subdev/clock/nv40.o |
45 | nouveau-y += core/subdev/clock/nv50.o | 51 | nouveau-y += core/subdev/clock/nv50.o |
@@ -85,9 +91,16 @@ nouveau-y += core/subdev/gpio/base.o | |||
85 | nouveau-y += core/subdev/gpio/nv10.o | 91 | nouveau-y += core/subdev/gpio/nv10.o |
86 | nouveau-y += core/subdev/gpio/nv50.o | 92 | nouveau-y += core/subdev/gpio/nv50.o |
87 | nouveau-y += core/subdev/gpio/nvd0.o | 93 | nouveau-y += core/subdev/gpio/nvd0.o |
94 | nouveau-y += core/subdev/gpio/nve0.o | ||
88 | nouveau-y += core/subdev/i2c/base.o | 95 | nouveau-y += core/subdev/i2c/base.o |
96 | nouveau-y += core/subdev/i2c/anx9805.o | ||
89 | nouveau-y += core/subdev/i2c/aux.o | 97 | nouveau-y += core/subdev/i2c/aux.o |
90 | nouveau-y += core/subdev/i2c/bit.o | 98 | nouveau-y += core/subdev/i2c/bit.o |
99 | nouveau-y += core/subdev/i2c/nv04.o | ||
100 | nouveau-y += core/subdev/i2c/nv4e.o | ||
101 | nouveau-y += core/subdev/i2c/nv50.o | ||
102 | nouveau-y += core/subdev/i2c/nv94.o | ||
103 | nouveau-y += core/subdev/i2c/nvd0.o | ||
91 | nouveau-y += core/subdev/ibus/nvc0.o | 104 | nouveau-y += core/subdev/ibus/nvc0.o |
92 | nouveau-y += core/subdev/ibus/nve0.o | 105 | nouveau-y += core/subdev/ibus/nve0.o |
93 | nouveau-y += core/subdev/instmem/base.o | 106 | nouveau-y += core/subdev/instmem/base.o |
@@ -106,10 +119,15 @@ nouveau-y += core/subdev/mxm/mxms.o | |||
106 | nouveau-y += core/subdev/mxm/nv50.o | 119 | nouveau-y += core/subdev/mxm/nv50.o |
107 | nouveau-y += core/subdev/therm/base.o | 120 | nouveau-y += core/subdev/therm/base.o |
108 | nouveau-y += core/subdev/therm/fan.o | 121 | nouveau-y += core/subdev/therm/fan.o |
122 | nouveau-y += core/subdev/therm/fannil.o | ||
123 | nouveau-y += core/subdev/therm/fanpwm.o | ||
124 | nouveau-y += core/subdev/therm/fantog.o | ||
109 | nouveau-y += core/subdev/therm/ic.o | 125 | nouveau-y += core/subdev/therm/ic.o |
126 | nouveau-y += core/subdev/therm/temp.o | ||
110 | nouveau-y += core/subdev/therm/nv40.o | 127 | nouveau-y += core/subdev/therm/nv40.o |
111 | nouveau-y += core/subdev/therm/nv50.o | 128 | nouveau-y += core/subdev/therm/nv50.o |
112 | nouveau-y += core/subdev/therm/temp.o | 129 | nouveau-y += core/subdev/therm/nva3.o |
130 | nouveau-y += core/subdev/therm/nvd0.o | ||
113 | nouveau-y += core/subdev/timer/base.o | 131 | nouveau-y += core/subdev/timer/base.o |
114 | nouveau-y += core/subdev/timer/nv04.o | 132 | nouveau-y += core/subdev/timer/nv04.o |
115 | nouveau-y += core/subdev/vm/base.o | 133 | nouveau-y += core/subdev/vm/base.o |
@@ -132,6 +150,7 @@ nouveau-y += core/engine/copy/nvc0.o | |||
132 | nouveau-y += core/engine/copy/nve0.o | 150 | nouveau-y += core/engine/copy/nve0.o |
133 | nouveau-y += core/engine/crypt/nv84.o | 151 | nouveau-y += core/engine/crypt/nv84.o |
134 | nouveau-y += core/engine/crypt/nv98.o | 152 | nouveau-y += core/engine/crypt/nv98.o |
153 | nouveau-y += core/engine/disp/base.o | ||
135 | nouveau-y += core/engine/disp/nv04.o | 154 | nouveau-y += core/engine/disp/nv04.o |
136 | nouveau-y += core/engine/disp/nv50.o | 155 | nouveau-y += core/engine/disp/nv50.o |
137 | nouveau-y += core/engine/disp/nv84.o | 156 | nouveau-y += core/engine/disp/nv84.o |
@@ -141,11 +160,13 @@ nouveau-y += core/engine/disp/nva3.o | |||
141 | nouveau-y += core/engine/disp/nvd0.o | 160 | nouveau-y += core/engine/disp/nvd0.o |
142 | nouveau-y += core/engine/disp/nve0.o | 161 | nouveau-y += core/engine/disp/nve0.o |
143 | nouveau-y += core/engine/disp/dacnv50.o | 162 | nouveau-y += core/engine/disp/dacnv50.o |
163 | nouveau-y += core/engine/disp/dport.o | ||
144 | nouveau-y += core/engine/disp/hdanva3.o | 164 | nouveau-y += core/engine/disp/hdanva3.o |
145 | nouveau-y += core/engine/disp/hdanvd0.o | 165 | nouveau-y += core/engine/disp/hdanvd0.o |
146 | nouveau-y += core/engine/disp/hdminv84.o | 166 | nouveau-y += core/engine/disp/hdminv84.o |
147 | nouveau-y += core/engine/disp/hdminva3.o | 167 | nouveau-y += core/engine/disp/hdminva3.o |
148 | nouveau-y += core/engine/disp/hdminvd0.o | 168 | nouveau-y += core/engine/disp/hdminvd0.o |
169 | nouveau-y += core/engine/disp/piornv50.o | ||
149 | nouveau-y += core/engine/disp/sornv50.o | 170 | nouveau-y += core/engine/disp/sornv50.o |
150 | nouveau-y += core/engine/disp/sornv94.o | 171 | nouveau-y += core/engine/disp/sornv94.o |
151 | nouveau-y += core/engine/disp/sornvd0.o | 172 | nouveau-y += core/engine/disp/sornvd0.o |
@@ -194,7 +215,8 @@ nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o | |||
194 | nouveau-y += nouveau_irq.o nouveau_vga.o nouveau_agp.o | 215 | nouveau-y += nouveau_irq.o nouveau_vga.o nouveau_agp.o |
195 | nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o | 216 | nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o |
196 | nouveau-y += nouveau_prime.o nouveau_abi16.o | 217 | nouveau-y += nouveau_prime.o nouveau_abi16.o |
197 | nouveau-y += nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o | 218 | nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o |
219 | nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o | ||
198 | 220 | ||
199 | # drm/kms | 221 | # drm/kms |
200 | nouveau-y += nouveau_bios.o nouveau_fbcon.o nouveau_display.o | 222 | nouveau-y += nouveau_bios.o nouveau_fbcon.o nouveau_display.o |
@@ -216,7 +238,9 @@ nouveau-y += nouveau_mem.o | |||
216 | 238 | ||
217 | # other random bits | 239 | # other random bits |
218 | nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o | 240 | nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o |
241 | ifdef CONFIG_X86 | ||
219 | nouveau-$(CONFIG_ACPI) += nouveau_acpi.o | 242 | nouveau-$(CONFIG_ACPI) += nouveau_acpi.o |
243 | endif | ||
220 | nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o | 244 | nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o |
221 | 245 | ||
222 | obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o | 246 | obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o |
diff --git a/drivers/gpu/drm/nouveau/core/core/client.c b/drivers/gpu/drm/nouveau/core/core/client.c index 8bbb58f94a19..295c22165eac 100644 --- a/drivers/gpu/drm/nouveau/core/core/client.c +++ b/drivers/gpu/drm/nouveau/core/core/client.c | |||
@@ -99,3 +99,13 @@ nouveau_client_fini(struct nouveau_client *client, bool suspend) | |||
99 | nv_debug(client, "%s completed with %d\n", name[suspend], ret); | 99 | nv_debug(client, "%s completed with %d\n", name[suspend], ret); |
100 | return ret; | 100 | return ret; |
101 | } | 101 | } |
102 | |||
103 | const char * | ||
104 | nouveau_client_name(void *obj) | ||
105 | { | ||
106 | const char *client_name = "unknown"; | ||
107 | struct nouveau_client *client = nouveau_client(obj); | ||
108 | if (client) | ||
109 | client_name = client->name; | ||
110 | return client_name; | ||
111 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/core/enum.c b/drivers/gpu/drm/nouveau/core/core/enum.c index 7cc7133d82de..dd434790ccc4 100644 --- a/drivers/gpu/drm/nouveau/core/core/enum.c +++ b/drivers/gpu/drm/nouveau/core/core/enum.c | |||
@@ -40,14 +40,15 @@ nouveau_enum_find(const struct nouveau_enum *en, u32 value) | |||
40 | return NULL; | 40 | return NULL; |
41 | } | 41 | } |
42 | 42 | ||
43 | void | 43 | const struct nouveau_enum * |
44 | nouveau_enum_print(const struct nouveau_enum *en, u32 value) | 44 | nouveau_enum_print(const struct nouveau_enum *en, u32 value) |
45 | { | 45 | { |
46 | en = nouveau_enum_find(en, value); | 46 | en = nouveau_enum_find(en, value); |
47 | if (en) | 47 | if (en) |
48 | printk("%s", en->name); | 48 | pr_cont("%s", en->name); |
49 | else | 49 | else |
50 | printk("(unknown enum 0x%08x)", value); | 50 | pr_cont("(unknown enum 0x%08x)", value); |
51 | return en; | ||
51 | } | 52 | } |
52 | 53 | ||
53 | void | 54 | void |
@@ -55,7 +56,7 @@ nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value) | |||
55 | { | 56 | { |
56 | while (bf->name) { | 57 | while (bf->name) { |
57 | if (value & bf->mask) { | 58 | if (value & bf->mask) { |
58 | printk(" %s", bf->name); | 59 | pr_cont(" %s", bf->name); |
59 | value &= ~bf->mask; | 60 | value &= ~bf->mask; |
60 | } | 61 | } |
61 | 62 | ||
@@ -63,5 +64,5 @@ nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value) | |||
63 | } | 64 | } |
64 | 65 | ||
65 | if (value) | 66 | if (value) |
66 | printk(" (unknown bits 0x%08x)", value); | 67 | pr_cont(" (unknown bits 0x%08x)", value); |
67 | } | 68 | } |
diff --git a/drivers/gpu/drm/nouveau/core/core/event.c b/drivers/gpu/drm/nouveau/core/core/event.c new file mode 100644 index 000000000000..6d01e0f0fc8a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/event.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <core/os.h> | ||
24 | #include <core/event.h> | ||
25 | |||
26 | static void | ||
27 | nouveau_event_put_locked(struct nouveau_event *event, int index, | ||
28 | struct nouveau_eventh *handler) | ||
29 | { | ||
30 | if (!--event->index[index].refs) | ||
31 | event->disable(event, index); | ||
32 | list_del(&handler->head); | ||
33 | } | ||
34 | |||
35 | void | ||
36 | nouveau_event_put(struct nouveau_event *event, int index, | ||
37 | struct nouveau_eventh *handler) | ||
38 | { | ||
39 | unsigned long flags; | ||
40 | |||
41 | spin_lock_irqsave(&event->lock, flags); | ||
42 | if (index < event->index_nr) | ||
43 | nouveau_event_put_locked(event, index, handler); | ||
44 | spin_unlock_irqrestore(&event->lock, flags); | ||
45 | } | ||
46 | |||
47 | void | ||
48 | nouveau_event_get(struct nouveau_event *event, int index, | ||
49 | struct nouveau_eventh *handler) | ||
50 | { | ||
51 | unsigned long flags; | ||
52 | |||
53 | spin_lock_irqsave(&event->lock, flags); | ||
54 | if (index < event->index_nr) { | ||
55 | list_add(&handler->head, &event->index[index].list); | ||
56 | if (!event->index[index].refs++) | ||
57 | event->enable(event, index); | ||
58 | } | ||
59 | spin_unlock_irqrestore(&event->lock, flags); | ||
60 | } | ||
61 | |||
62 | void | ||
63 | nouveau_event_trigger(struct nouveau_event *event, int index) | ||
64 | { | ||
65 | struct nouveau_eventh *handler, *temp; | ||
66 | unsigned long flags; | ||
67 | |||
68 | if (index >= event->index_nr) | ||
69 | return; | ||
70 | |||
71 | spin_lock_irqsave(&event->lock, flags); | ||
72 | list_for_each_entry_safe(handler, temp, &event->index[index].list, head) { | ||
73 | if (handler->func(handler, index) == NVKM_EVENT_DROP) { | ||
74 | nouveau_event_put_locked(event, index, handler); | ||
75 | } | ||
76 | } | ||
77 | spin_unlock_irqrestore(&event->lock, flags); | ||
78 | } | ||
79 | |||
80 | void | ||
81 | nouveau_event_destroy(struct nouveau_event **pevent) | ||
82 | { | ||
83 | struct nouveau_event *event = *pevent; | ||
84 | if (event) { | ||
85 | kfree(event); | ||
86 | *pevent = NULL; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | int | ||
91 | nouveau_event_create(int index_nr, struct nouveau_event **pevent) | ||
92 | { | ||
93 | struct nouveau_event *event; | ||
94 | int i; | ||
95 | |||
96 | event = *pevent = kzalloc(sizeof(*event) + index_nr * | ||
97 | sizeof(event->index[0]), GFP_KERNEL); | ||
98 | if (!event) | ||
99 | return -ENOMEM; | ||
100 | |||
101 | spin_lock_init(&event->lock); | ||
102 | for (i = 0; i < index_nr; i++) | ||
103 | INIT_LIST_HEAD(&event->index[i].list); | ||
104 | event->index_nr = index_nr; | ||
105 | return 0; | ||
106 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c index 283248c7b050..d6dc2a65ccd1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/client.h> | ||
25 | #include <core/falcon.h> | 26 | #include <core/falcon.h> |
26 | #include <core/class.h> | 27 | #include <core/class.h> |
27 | #include <core/enum.h> | 28 | #include <core/enum.h> |
@@ -100,8 +101,9 @@ nva3_copy_intr(struct nouveau_subdev *subdev) | |||
100 | if (stat & 0x00000040) { | 101 | if (stat & 0x00000040) { |
101 | nv_error(falcon, "DISPATCH_ERROR ["); | 102 | nv_error(falcon, "DISPATCH_ERROR ["); |
102 | nouveau_enum_print(nva3_copy_isr_error_name, ssta); | 103 | nouveau_enum_print(nva3_copy_isr_error_name, ssta); |
103 | printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n", | 104 | pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n", |
104 | chid, inst << 12, subc, mthd, data); | 105 | chid, inst << 12, nouveau_client_name(engctx), subc, |
106 | mthd, data); | ||
105 | nv_wo32(falcon, 0x004, 0x00000040); | 107 | nv_wo32(falcon, 0x004, 0x00000040); |
106 | stat &= ~0x00000040; | 108 | stat &= ~0x00000040; |
107 | } | 109 | } |
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c index b97490512723..5bc021f471f9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/client.h> | ||
25 | #include <core/os.h> | 26 | #include <core/os.h> |
26 | #include <core/enum.h> | 27 | #include <core/enum.h> |
27 | #include <core/class.h> | 28 | #include <core/class.h> |
@@ -126,10 +127,11 @@ nv84_crypt_intr(struct nouveau_subdev *subdev) | |||
126 | chid = pfifo->chid(pfifo, engctx); | 127 | chid = pfifo->chid(pfifo, engctx); |
127 | 128 | ||
128 | if (stat) { | 129 | if (stat) { |
129 | nv_error(priv, ""); | 130 | nv_error(priv, "%s", ""); |
130 | nouveau_bitfield_print(nv84_crypt_intr_mask, stat); | 131 | nouveau_bitfield_print(nv84_crypt_intr_mask, stat); |
131 | printk(" ch %d [0x%010llx] mthd 0x%04x data 0x%08x\n", | 132 | pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n", |
132 | chid, (u64)inst << 12, mthd, data); | 133 | chid, (u64)inst << 12, nouveau_client_name(engctx), |
134 | mthd, data); | ||
133 | } | 135 | } |
134 | 136 | ||
135 | nv_wr32(priv, 0x102130, stat); | 137 | nv_wr32(priv, 0x102130, stat); |
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c index 21986f3bf0c8..8bf8955051d4 100644 --- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c +++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/client.h> | ||
25 | #include <core/os.h> | 26 | #include <core/os.h> |
26 | #include <core/enum.h> | 27 | #include <core/enum.h> |
27 | #include <core/class.h> | 28 | #include <core/class.h> |
@@ -102,8 +103,9 @@ nv98_crypt_intr(struct nouveau_subdev *subdev) | |||
102 | if (stat & 0x00000040) { | 103 | if (stat & 0x00000040) { |
103 | nv_error(priv, "DISPATCH_ERROR ["); | 104 | nv_error(priv, "DISPATCH_ERROR ["); |
104 | nouveau_enum_print(nv98_crypt_isr_error_name, ssta); | 105 | nouveau_enum_print(nv98_crypt_isr_error_name, ssta); |
105 | printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n", | 106 | pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n", |
106 | chid, (u64)inst << 12, subc, mthd, data); | 107 | chid, (u64)inst << 12, nouveau_client_name(engctx), |
108 | subc, mthd, data); | ||
107 | nv_wr32(priv, 0x087004, 0x00000040); | 109 | nv_wr32(priv, 0x087004, 0x00000040); |
108 | stat &= ~0x00000040; | 110 | stat &= ~0x00000040; |
109 | } | 111 | } |
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/base.c b/drivers/gpu/drm/nouveau/core/engine/disp/base.c new file mode 100644 index 000000000000..7a5cae42834f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/base.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Copyright 2013 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 <engine/disp.h> | ||
26 | |||
27 | void | ||
28 | _nouveau_disp_dtor(struct nouveau_object *object) | ||
29 | { | ||
30 | struct nouveau_disp *disp = (void *)object; | ||
31 | nouveau_event_destroy(&disp->vblank); | ||
32 | nouveau_engine_destroy(&disp->base); | ||
33 | } | ||
34 | |||
35 | int | ||
36 | nouveau_disp_create_(struct nouveau_object *parent, | ||
37 | struct nouveau_object *engine, | ||
38 | struct nouveau_oclass *oclass, int heads, | ||
39 | const char *intname, const char *extname, | ||
40 | int length, void **pobject) | ||
41 | { | ||
42 | struct nouveau_disp *disp; | ||
43 | int ret; | ||
44 | |||
45 | ret = nouveau_engine_create_(parent, engine, oclass, true, | ||
46 | intname, extname, length, pobject); | ||
47 | disp = *pobject; | ||
48 | if (ret) | ||
49 | return ret; | ||
50 | |||
51 | return nouveau_event_create(heads, &disp->vblank); | ||
52 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c new file mode 100644 index 000000000000..fa27b02ff829 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Ben Skeggs | ||
23 | */ | ||
24 | |||
25 | #include <subdev/bios.h> | ||
26 | #include <subdev/bios/dcb.h> | ||
27 | #include <subdev/bios/dp.h> | ||
28 | #include <subdev/bios/init.h> | ||
29 | #include <subdev/i2c.h> | ||
30 | |||
31 | #include <engine/disp.h> | ||
32 | |||
33 | #include "dport.h" | ||
34 | |||
35 | #define DBG(fmt, args...) nv_debug(dp->disp, "DP:%04x:%04x: " fmt, \ | ||
36 | dp->outp->hasht, dp->outp->hashm, ##args) | ||
37 | #define ERR(fmt, args...) nv_error(dp->disp, "DP:%04x:%04x: " fmt, \ | ||
38 | dp->outp->hasht, dp->outp->hashm, ##args) | ||
39 | |||
40 | /****************************************************************************** | ||
41 | * link training | ||
42 | *****************************************************************************/ | ||
43 | struct dp_state { | ||
44 | const struct nouveau_dp_func *func; | ||
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[4]; | ||
52 | int link_nr; | ||
53 | u32 link_bw; | ||
54 | u8 stat[6]; | ||
55 | u8 conf[4]; | ||
56 | }; | ||
57 | |||
58 | static int | ||
59 | dp_set_link_config(struct dp_state *dp) | ||
60 | { | ||
61 | struct nouveau_disp *disp = dp->disp; | ||
62 | struct nouveau_bios *bios = nouveau_bios(disp); | ||
63 | struct nvbios_init init = { | ||
64 | .subdev = nv_subdev(dp->disp), | ||
65 | .bios = bios, | ||
66 | .offset = 0x0000, | ||
67 | .outp = dp->outp, | ||
68 | .crtc = dp->head, | ||
69 | .execute = 1, | ||
70 | }; | ||
71 | u32 lnkcmp; | ||
72 | u8 sink[2]; | ||
73 | |||
74 | DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); | ||
75 | |||
76 | /* set desired link configuration on the sink */ | ||
77 | sink[0] = dp->link_bw / 27000; | ||
78 | sink[1] = dp->link_nr; | ||
79 | if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) | ||
80 | sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; | ||
81 | |||
82 | nv_wraux(dp->aux, DPCD_LC00, sink, 2); | ||
83 | |||
84 | /* set desired link configuration on the source */ | ||
85 | if ((lnkcmp = dp->info.lnkcmp)) { | ||
86 | if (dp->version < 0x30) { | ||
87 | while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp)) | ||
88 | lnkcmp += 4; | ||
89 | init.offset = nv_ro16(bios, lnkcmp + 2); | ||
90 | } else { | ||
91 | while ((dp->link_bw / 27000) < nv_ro08(bios, lnkcmp)) | ||
92 | lnkcmp += 3; | ||
93 | init.offset = nv_ro16(bios, lnkcmp + 1); | ||
94 | } | ||
95 | |||
96 | nvbios_exec(&init); | ||
97 | } | ||
98 | |||
99 | return dp->func->lnk_ctl(dp->disp, dp->outp, dp->head, | ||
100 | dp->link_nr, dp->link_bw / 27000, | ||
101 | dp->dpcd[DPCD_RC02] & | ||
102 | DPCD_RC02_ENHANCED_FRAME_CAP); | ||
103 | } | ||
104 | |||
105 | static void | ||
106 | dp_set_training_pattern(struct dp_state *dp, u8 pattern) | ||
107 | { | ||
108 | u8 sink_tp; | ||
109 | |||
110 | DBG("training pattern %d\n", pattern); | ||
111 | dp->func->pattern(dp->disp, dp->outp, dp->head, pattern); | ||
112 | |||
113 | nv_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); | ||
114 | sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; | ||
115 | sink_tp |= pattern; | ||
116 | nv_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); | ||
117 | } | ||
118 | |||
119 | static int | ||
120 | dp_link_train_commit(struct dp_state *dp) | ||
121 | { | ||
122 | int i; | ||
123 | |||
124 | for (i = 0; i < dp->link_nr; i++) { | ||
125 | u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; | ||
126 | u8 lpre = (lane & 0x0c) >> 2; | ||
127 | u8 lvsw = (lane & 0x03) >> 0; | ||
128 | |||
129 | dp->conf[i] = (lpre << 3) | lvsw; | ||
130 | if (lvsw == 3) | ||
131 | dp->conf[i] |= DPCD_LC03_MAX_SWING_REACHED; | ||
132 | if (lpre == 3) | ||
133 | dp->conf[i] |= DPCD_LC03_MAX_PRE_EMPHASIS_REACHED; | ||
134 | |||
135 | DBG("config lane %d %02x\n", i, dp->conf[i]); | ||
136 | dp->func->drv_ctl(dp->disp, dp->outp, dp->head, i, lvsw, lpre); | ||
137 | } | ||
138 | |||
139 | return nv_wraux(dp->aux, DPCD_LC03(0), dp->conf, 4); | ||
140 | } | ||
141 | |||
142 | static int | ||
143 | dp_link_train_update(struct dp_state *dp, u32 delay) | ||
144 | { | ||
145 | int ret; | ||
146 | |||
147 | udelay(delay); | ||
148 | |||
149 | ret = nv_rdaux(dp->aux, DPCD_LS02, dp->stat, 6); | ||
150 | if (ret) | ||
151 | return ret; | ||
152 | |||
153 | DBG("status %*ph\n", 6, dp->stat); | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int | ||
158 | dp_link_train_cr(struct dp_state *dp) | ||
159 | { | ||
160 | bool cr_done = false, abort = false; | ||
161 | int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET; | ||
162 | int tries = 0, i; | ||
163 | |||
164 | dp_set_training_pattern(dp, 1); | ||
165 | |||
166 | do { | ||
167 | if (dp_link_train_commit(dp) || | ||
168 | dp_link_train_update(dp, 100)) | ||
169 | break; | ||
170 | |||
171 | cr_done = true; | ||
172 | for (i = 0; i < dp->link_nr; i++) { | ||
173 | u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; | ||
174 | if (!(lane & DPCD_LS02_LANE0_CR_DONE)) { | ||
175 | cr_done = false; | ||
176 | if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED) | ||
177 | abort = true; | ||
178 | break; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) { | ||
183 | voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET; | ||
184 | tries = 0; | ||
185 | } | ||
186 | } while (!cr_done && !abort && ++tries < 5); | ||
187 | |||
188 | return cr_done ? 0 : -1; | ||
189 | } | ||
190 | |||
191 | static int | ||
192 | dp_link_train_eq(struct dp_state *dp) | ||
193 | { | ||
194 | bool eq_done, cr_done = true; | ||
195 | int tries = 0, i; | ||
196 | |||
197 | dp_set_training_pattern(dp, 2); | ||
198 | |||
199 | do { | ||
200 | if (dp_link_train_update(dp, 400)) | ||
201 | break; | ||
202 | |||
203 | eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); | ||
204 | for (i = 0; i < dp->link_nr && eq_done; i++) { | ||
205 | u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; | ||
206 | if (!(lane & DPCD_LS02_LANE0_CR_DONE)) | ||
207 | cr_done = false; | ||
208 | if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || | ||
209 | !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) | ||
210 | eq_done = false; | ||
211 | } | ||
212 | |||
213 | if (dp_link_train_commit(dp)) | ||
214 | break; | ||
215 | } while (!eq_done && cr_done && ++tries <= 5); | ||
216 | |||
217 | return eq_done ? 0 : -1; | ||
218 | } | ||
219 | |||
220 | static void | ||
221 | dp_link_train_init(struct dp_state *dp, bool spread) | ||
222 | { | ||
223 | struct nvbios_init init = { | ||
224 | .subdev = nv_subdev(dp->disp), | ||
225 | .bios = nouveau_bios(dp->disp), | ||
226 | .outp = dp->outp, | ||
227 | .crtc = dp->head, | ||
228 | .execute = 1, | ||
229 | }; | ||
230 | |||
231 | /* set desired spread */ | ||
232 | if (spread) | ||
233 | init.offset = dp->info.script[2]; | ||
234 | else | ||
235 | init.offset = dp->info.script[3]; | ||
236 | nvbios_exec(&init); | ||
237 | |||
238 | /* pre-train script */ | ||
239 | init.offset = dp->info.script[0]; | ||
240 | nvbios_exec(&init); | ||
241 | } | ||
242 | |||
243 | static void | ||
244 | dp_link_train_fini(struct dp_state *dp) | ||
245 | { | ||
246 | struct nvbios_init init = { | ||
247 | .subdev = nv_subdev(dp->disp), | ||
248 | .bios = nouveau_bios(dp->disp), | ||
249 | .outp = dp->outp, | ||
250 | .crtc = dp->head, | ||
251 | .execute = 1, | ||
252 | }; | ||
253 | |||
254 | /* post-train script */ | ||
255 | init.offset = dp->info.script[1], | ||
256 | nvbios_exec(&init); | ||
257 | } | ||
258 | |||
259 | int | ||
260 | nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, | ||
261 | struct dcb_output *outp, int head, u32 datarate) | ||
262 | { | ||
263 | struct nouveau_bios *bios = nouveau_bios(disp); | ||
264 | struct nouveau_i2c *i2c = nouveau_i2c(disp); | ||
265 | struct dp_state _dp = { | ||
266 | .disp = disp, | ||
267 | .func = func, | ||
268 | .outp = outp, | ||
269 | .head = head, | ||
270 | }, *dp = &_dp; | ||
271 | const u32 bw_list[] = { 270000, 162000, 0 }; | ||
272 | const u32 *link_bw = bw_list; | ||
273 | u8 hdr, cnt, len; | ||
274 | u32 data; | ||
275 | int ret; | ||
276 | |||
277 | /* find the bios displayport data relevant to this output */ | ||
278 | data = nvbios_dpout_match(bios, outp->hasht, outp->hashm, &dp->version, | ||
279 | &hdr, &cnt, &len, &dp->info); | ||
280 | if (!data) { | ||
281 | ERR("bios data not found\n"); | ||
282 | return -EINVAL; | ||
283 | } | ||
284 | |||
285 | /* acquire the aux channel and fetch some info about the display */ | ||
286 | if (outp->location) | ||
287 | dp->aux = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev)); | ||
288 | else | ||
289 | dp->aux = i2c->find(i2c, NV_I2C_TYPE_DCBI2C(outp->i2c_index)); | ||
290 | if (!dp->aux) { | ||
291 | ERR("no aux channel?!\n"); | ||
292 | return -ENODEV; | ||
293 | } | ||
294 | |||
295 | ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd)); | ||
296 | if (ret) { | ||
297 | ERR("failed to read DPCD\n"); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | /* adjust required bandwidth for 8B/10B coding overhead */ | ||
302 | datarate = (datarate / 8) * 10; | ||
303 | |||
304 | /* enable down-spreading and execute pre-train script from vbios */ | ||
305 | dp_link_train_init(dp, dp->dpcd[3] & 0x01); | ||
306 | |||
307 | /* start off at highest link rate supported by encoder and display */ | ||
308 | while (*link_bw > (dp->dpcd[1] * 27000)) | ||
309 | link_bw++; | ||
310 | |||
311 | while (link_bw[0]) { | ||
312 | /* find minimum required lane count at this link rate */ | ||
313 | dp->link_nr = dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT; | ||
314 | while ((dp->link_nr >> 1) * link_bw[0] > datarate) | ||
315 | dp->link_nr >>= 1; | ||
316 | |||
317 | /* drop link rate to minimum with this lane count */ | ||
318 | while ((link_bw[1] * dp->link_nr) > datarate) | ||
319 | link_bw++; | ||
320 | dp->link_bw = link_bw[0]; | ||
321 | |||
322 | /* program selected link configuration */ | ||
323 | ret = dp_set_link_config(dp); | ||
324 | if (ret == 0) { | ||
325 | /* attempt to train the link at this configuration */ | ||
326 | memset(dp->stat, 0x00, sizeof(dp->stat)); | ||
327 | if (!dp_link_train_cr(dp) && | ||
328 | !dp_link_train_eq(dp)) | ||
329 | break; | ||
330 | } else | ||
331 | if (ret >= 1) { | ||
332 | /* dp_set_link_config() handled training */ | ||
333 | break; | ||
334 | } | ||
335 | |||
336 | /* retry at lower rate */ | ||
337 | link_bw++; | ||
338 | } | ||
339 | |||
340 | /* finish link training */ | ||
341 | dp_set_training_pattern(dp, 0); | ||
342 | |||
343 | /* execute post-train script from vbios */ | ||
344 | dp_link_train_fini(dp); | ||
345 | return true; | ||
346 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h b/drivers/gpu/drm/nouveau/core/engine/disp/dport.h new file mode 100644 index 000000000000..0e1bbd18ff6c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.h | |||
@@ -0,0 +1,78 @@ | |||
1 | #ifndef __NVKM_DISP_DPORT_H__ | ||
2 | #define __NVKM_DISP_DPORT_H__ | ||
3 | |||
4 | /* DPCD Receiver Capabilities */ | ||
5 | #define DPCD_RC00 0x00000 | ||
6 | #define DPCD_RC00_DPCD_REV 0xff | ||
7 | #define DPCD_RC01 0x00001 | ||
8 | #define DPCD_RC01_MAX_LINK_RATE 0xff | ||
9 | #define DPCD_RC02 0x00002 | ||
10 | #define DPCD_RC02_ENHANCED_FRAME_CAP 0x80 | ||
11 | #define DPCD_RC02_MAX_LANE_COUNT 0x1f | ||
12 | #define DPCD_RC03 0x00003 | ||
13 | #define DPCD_RC03_MAX_DOWNSPREAD 0x01 | ||
14 | |||
15 | /* DPCD Link Configuration */ | ||
16 | #define DPCD_LC00 0x00100 | ||
17 | #define DPCD_LC00_LINK_BW_SET 0xff | ||
18 | #define DPCD_LC01 0x00101 | ||
19 | #define DPCD_LC01_ENHANCED_FRAME_EN 0x80 | ||
20 | #define DPCD_LC01_LANE_COUNT_SET 0x1f | ||
21 | #define DPCD_LC02 0x00102 | ||
22 | #define DPCD_LC02_TRAINING_PATTERN_SET 0x03 | ||
23 | #define DPCD_LC03(l) ((l) + 0x00103) | ||
24 | #define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20 | ||
25 | #define DPCD_LC03_PRE_EMPHASIS_SET 0x18 | ||
26 | #define DPCD_LC03_MAX_SWING_REACHED 0x04 | ||
27 | #define DPCD_LC03_VOLTAGE_SWING_SET 0x03 | ||
28 | |||
29 | /* DPCD Link/Sink Status */ | ||
30 | #define DPCD_LS02 0x00202 | ||
31 | #define DPCD_LS02_LANE1_SYMBOL_LOCKED 0x40 | ||
32 | #define DPCD_LS02_LANE1_CHANNEL_EQ_DONE 0x20 | ||
33 | #define DPCD_LS02_LANE1_CR_DONE 0x10 | ||
34 | #define DPCD_LS02_LANE0_SYMBOL_LOCKED 0x04 | ||
35 | #define DPCD_LS02_LANE0_CHANNEL_EQ_DONE 0x02 | ||
36 | #define DPCD_LS02_LANE0_CR_DONE 0x01 | ||
37 | #define DPCD_LS03 0x00203 | ||
38 | #define DPCD_LS03_LANE3_SYMBOL_LOCKED 0x40 | ||
39 | #define DPCD_LS03_LANE3_CHANNEL_EQ_DONE 0x20 | ||
40 | #define DPCD_LS03_LANE3_CR_DONE 0x10 | ||
41 | #define DPCD_LS03_LANE2_SYMBOL_LOCKED 0x04 | ||
42 | #define DPCD_LS03_LANE2_CHANNEL_EQ_DONE 0x02 | ||
43 | #define DPCD_LS03_LANE2_CR_DONE 0x01 | ||
44 | #define DPCD_LS04 0x00204 | ||
45 | #define DPCD_LS04_LINK_STATUS_UPDATED 0x80 | ||
46 | #define DPCD_LS04_DOWNSTREAM_PORT_STATUS_CHANGED 0x40 | ||
47 | #define DPCD_LS04_INTERLANE_ALIGN_DONE 0x01 | ||
48 | #define DPCD_LS06 0x00206 | ||
49 | #define DPCD_LS06_LANE1_PRE_EMPHASIS 0xc0 | ||
50 | #define DPCD_LS06_LANE1_VOLTAGE_SWING 0x30 | ||
51 | #define DPCD_LS06_LANE0_PRE_EMPHASIS 0x0c | ||
52 | #define DPCD_LS06_LANE0_VOLTAGE_SWING 0x03 | ||
53 | #define DPCD_LS07 0x00207 | ||
54 | #define DPCD_LS07_LANE3_PRE_EMPHASIS 0xc0 | ||
55 | #define DPCD_LS07_LANE3_VOLTAGE_SWING 0x30 | ||
56 | #define DPCD_LS07_LANE2_PRE_EMPHASIS 0x0c | ||
57 | #define DPCD_LS07_LANE2_VOLTAGE_SWING 0x03 | ||
58 | |||
59 | struct nouveau_disp; | ||
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 | |||
78 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c index 1c919f2af89f..05e903f08a36 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c | |||
@@ -24,21 +24,33 @@ | |||
24 | 24 | ||
25 | #include <engine/disp.h> | 25 | #include <engine/disp.h> |
26 | 26 | ||
27 | #include <core/event.h> | ||
28 | #include <core/class.h> | ||
29 | |||
27 | struct nv04_disp_priv { | 30 | struct nv04_disp_priv { |
28 | struct nouveau_disp base; | 31 | struct nouveau_disp base; |
29 | }; | 32 | }; |
30 | 33 | ||
31 | static struct nouveau_oclass | 34 | static struct nouveau_oclass |
32 | nv04_disp_sclass[] = { | 35 | nv04_disp_sclass[] = { |
36 | { NV04_DISP_CLASS, &nouveau_object_ofuncs }, | ||
33 | {}, | 37 | {}, |
34 | }; | 38 | }; |
35 | 39 | ||
40 | /******************************************************************************* | ||
41 | * Display engine implementation | ||
42 | ******************************************************************************/ | ||
43 | |||
44 | static void | ||
45 | nv04_disp_vblank_enable(struct nouveau_event *event, int head) | ||
46 | { | ||
47 | nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001); | ||
48 | } | ||
49 | |||
36 | static void | 50 | static void |
37 | nv04_disp_intr_vblank(struct nv04_disp_priv *priv, int crtc) | 51 | nv04_disp_vblank_disable(struct nouveau_event *event, int head) |
38 | { | 52 | { |
39 | struct nouveau_disp *disp = &priv->base; | 53 | nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000); |
40 | if (disp->vblank.notify) | ||
41 | disp->vblank.notify(disp->vblank.data, crtc); | ||
42 | } | 54 | } |
43 | 55 | ||
44 | static void | 56 | static void |
@@ -49,25 +61,25 @@ nv04_disp_intr(struct nouveau_subdev *subdev) | |||
49 | u32 crtc1 = nv_rd32(priv, 0x602100); | 61 | u32 crtc1 = nv_rd32(priv, 0x602100); |
50 | 62 | ||
51 | if (crtc0 & 0x00000001) { | 63 | if (crtc0 & 0x00000001) { |
52 | nv04_disp_intr_vblank(priv, 0); | 64 | nouveau_event_trigger(priv->base.vblank, 0); |
53 | nv_wr32(priv, 0x600100, 0x00000001); | 65 | nv_wr32(priv, 0x600100, 0x00000001); |
54 | } | 66 | } |
55 | 67 | ||
56 | if (crtc1 & 0x00000001) { | 68 | if (crtc1 & 0x00000001) { |
57 | nv04_disp_intr_vblank(priv, 1); | 69 | nouveau_event_trigger(priv->base.vblank, 1); |
58 | nv_wr32(priv, 0x602100, 0x00000001); | 70 | nv_wr32(priv, 0x602100, 0x00000001); |
59 | } | 71 | } |
60 | } | 72 | } |
61 | 73 | ||
62 | static int | 74 | static int |
63 | nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 75 | nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
64 | struct nouveau_oclass *oclass, void *data, u32 size, | 76 | struct nouveau_oclass *oclass, void *data, u32 size, |
65 | struct nouveau_object **pobject) | 77 | struct nouveau_object **pobject) |
66 | { | 78 | { |
67 | struct nv04_disp_priv *priv; | 79 | struct nv04_disp_priv *priv; |
68 | int ret; | 80 | int ret; |
69 | 81 | ||
70 | ret = nouveau_disp_create(parent, engine, oclass, "DISPLAY", | 82 | ret = nouveau_disp_create(parent, engine, oclass, 2, "DISPLAY", |
71 | "display", &priv); | 83 | "display", &priv); |
72 | *pobject = nv_object(priv); | 84 | *pobject = nv_object(priv); |
73 | if (ret) | 85 | if (ret) |
@@ -75,6 +87,9 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
75 | 87 | ||
76 | nv_engine(priv)->sclass = nv04_disp_sclass; | 88 | nv_engine(priv)->sclass = nv04_disp_sclass; |
77 | nv_subdev(priv)->intr = nv04_disp_intr; | 89 | nv_subdev(priv)->intr = nv04_disp_intr; |
90 | priv->base.vblank->priv = priv; | ||
91 | priv->base.vblank->enable = nv04_disp_vblank_enable; | ||
92 | priv->base.vblank->disable = nv04_disp_vblank_disable; | ||
78 | return 0; | 93 | return 0; |
79 | } | 94 | } |
80 | 95 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index ca1a7d76a95b..314dda6d7cb8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <core/handle.h> | 27 | #include <core/handle.h> |
28 | #include <core/class.h> | 28 | #include <core/class.h> |
29 | 29 | ||
30 | #include <engine/software.h> | ||
31 | #include <engine/disp.h> | 30 | #include <engine/disp.h> |
32 | 31 | ||
33 | #include <subdev/bios.h> | 32 | #include <subdev/bios.h> |
@@ -37,7 +36,6 @@ | |||
37 | #include <subdev/bios/pll.h> | 36 | #include <subdev/bios/pll.h> |
38 | #include <subdev/timer.h> | 37 | #include <subdev/timer.h> |
39 | #include <subdev/fb.h> | 38 | #include <subdev/fb.h> |
40 | #include <subdev/bar.h> | ||
41 | #include <subdev/clock.h> | 39 | #include <subdev/clock.h> |
42 | 40 | ||
43 | #include "nv50.h" | 41 | #include "nv50.h" |
@@ -335,7 +333,7 @@ nv50_disp_sync_ctor(struct nouveau_object *parent, | |||
335 | struct nv50_disp_dmac *dmac; | 333 | struct nv50_disp_dmac *dmac; |
336 | int ret; | 334 | int ret; |
337 | 335 | ||
338 | if (size < sizeof(*data) || args->head > 1) | 336 | if (size < sizeof(*args) || args->head > 1) |
339 | return -EINVAL; | 337 | return -EINVAL; |
340 | 338 | ||
341 | ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, | 339 | ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, |
@@ -374,7 +372,7 @@ nv50_disp_ovly_ctor(struct nouveau_object *parent, | |||
374 | struct nv50_disp_dmac *dmac; | 372 | struct nv50_disp_dmac *dmac; |
375 | int ret; | 373 | int ret; |
376 | 374 | ||
377 | if (size < sizeof(*data) || args->head > 1) | 375 | if (size < sizeof(*args) || args->head > 1) |
378 | return -EINVAL; | 376 | return -EINVAL; |
379 | 377 | ||
380 | ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, | 378 | ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, |
@@ -543,6 +541,18 @@ nv50_disp_curs_ofuncs = { | |||
543 | * Base display object | 541 | * Base display object |
544 | ******************************************************************************/ | 542 | ******************************************************************************/ |
545 | 543 | ||
544 | static void | ||
545 | nv50_disp_base_vblank_enable(struct nouveau_event *event, int head) | ||
546 | { | ||
547 | nv_mask(event->priv, 0x61002c, (1 << head), (1 << head)); | ||
548 | } | ||
549 | |||
550 | static void | ||
551 | nv50_disp_base_vblank_disable(struct nouveau_event *event, int head) | ||
552 | { | ||
553 | nv_mask(event->priv, 0x61002c, (1 << head), (0 << head)); | ||
554 | } | ||
555 | |||
546 | static int | 556 | static int |
547 | nv50_disp_base_ctor(struct nouveau_object *parent, | 557 | nv50_disp_base_ctor(struct nouveau_object *parent, |
548 | struct nouveau_object *engine, | 558 | struct nouveau_object *engine, |
@@ -559,6 +569,9 @@ nv50_disp_base_ctor(struct nouveau_object *parent, | |||
559 | if (ret) | 569 | if (ret) |
560 | return ret; | 570 | return ret; |
561 | 571 | ||
572 | priv->base.vblank->priv = priv; | ||
573 | priv->base.vblank->enable = nv50_disp_base_vblank_enable; | ||
574 | priv->base.vblank->disable = nv50_disp_base_vblank_disable; | ||
562 | return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht); | 575 | return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht); |
563 | } | 576 | } |
564 | 577 | ||
@@ -613,7 +626,7 @@ nv50_disp_base_init(struct nouveau_object *object) | |||
613 | nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp); | 626 | nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp); |
614 | } | 627 | } |
615 | 628 | ||
616 | /* ... EXT caps */ | 629 | /* ... PIOR caps */ |
617 | for (i = 0; i < 3; i++) { | 630 | for (i = 0; i < 3; i++) { |
618 | tmp = nv_rd32(priv, 0x61e000 + (i * 0x800)); | 631 | tmp = nv_rd32(priv, 0x61e000 + (i * 0x800)); |
619 | nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp); | 632 | nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp); |
@@ -665,6 +678,9 @@ nv50_disp_base_omthds[] = { | |||
665 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, | 678 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, |
666 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, | 679 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, |
667 | { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, | 680 | { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, |
681 | { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, | ||
682 | { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, | ||
683 | { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd }, | ||
668 | {}, | 684 | {}, |
669 | }; | 685 | }; |
670 | 686 | ||
@@ -756,50 +772,6 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv) | |||
756 | } | 772 | } |
757 | } | 773 | } |
758 | 774 | ||
759 | static void | ||
760 | nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) | ||
761 | { | ||
762 | struct nouveau_bar *bar = nouveau_bar(priv); | ||
763 | struct nouveau_disp *disp = &priv->base; | ||
764 | struct nouveau_software_chan *chan, *temp; | ||
765 | unsigned long flags; | ||
766 | |||
767 | spin_lock_irqsave(&disp->vblank.lock, flags); | ||
768 | list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) { | ||
769 | if (chan->vblank.crtc != crtc) | ||
770 | continue; | ||
771 | |||
772 | if (nv_device(priv)->chipset >= 0xc0) { | ||
773 | nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); | ||
774 | bar->flush(bar); | ||
775 | nv_wr32(priv, 0x06000c, | ||
776 | upper_32_bits(chan->vblank.offset)); | ||
777 | nv_wr32(priv, 0x060010, | ||
778 | lower_32_bits(chan->vblank.offset)); | ||
779 | nv_wr32(priv, 0x060014, chan->vblank.value); | ||
780 | } else { | ||
781 | nv_wr32(priv, 0x001704, chan->vblank.channel); | ||
782 | nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); | ||
783 | bar->flush(bar); | ||
784 | if (nv_device(priv)->chipset == 0x50) { | ||
785 | nv_wr32(priv, 0x001570, chan->vblank.offset); | ||
786 | nv_wr32(priv, 0x001574, chan->vblank.value); | ||
787 | } else { | ||
788 | nv_wr32(priv, 0x060010, chan->vblank.offset); | ||
789 | nv_wr32(priv, 0x060014, chan->vblank.value); | ||
790 | } | ||
791 | } | ||
792 | |||
793 | list_del(&chan->vblank.head); | ||
794 | if (disp->vblank.put) | ||
795 | disp->vblank.put(disp->vblank.data, crtc); | ||
796 | } | ||
797 | spin_unlock_irqrestore(&disp->vblank.lock, flags); | ||
798 | |||
799 | if (disp->vblank.notify) | ||
800 | disp->vblank.notify(disp->vblank.data, crtc); | ||
801 | } | ||
802 | |||
803 | static u16 | 775 | static u16 |
804 | exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, | 776 | exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, |
805 | struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, | 777 | struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, |
@@ -811,8 +783,8 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, | |||
811 | if (outp < 4) { | 783 | if (outp < 4) { |
812 | type = DCB_OUTPUT_ANALOG; | 784 | type = DCB_OUTPUT_ANALOG; |
813 | mask = 0; | 785 | mask = 0; |
814 | } else { | 786 | } else |
815 | outp -= 4; | 787 | if (outp < 8) { |
816 | switch (ctrl & 0x00000f00) { | 788 | switch (ctrl & 0x00000f00) { |
817 | case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; | 789 | case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; |
818 | case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; | 790 | case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; |
@@ -824,6 +796,17 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, | |||
824 | nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); | 796 | nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); |
825 | return 0x0000; | 797 | return 0x0000; |
826 | } | 798 | } |
799 | outp -= 4; | ||
800 | } else { | ||
801 | outp = outp - 8; | ||
802 | type = 0x0010; | ||
803 | mask = 0; | ||
804 | switch (ctrl & 0x00000f00) { | ||
805 | case 0x00000000: type |= priv->pior.type[outp]; break; | ||
806 | default: | ||
807 | nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl); | ||
808 | return 0x0000; | ||
809 | } | ||
827 | } | 810 | } |
828 | 811 | ||
829 | mask = 0x00c0 & (mask << 6); | 812 | mask = 0x00c0 & (mask << 6); |
@@ -834,6 +817,10 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, | |||
834 | if (!data) | 817 | if (!data) |
835 | return 0x0000; | 818 | return 0x0000; |
836 | 819 | ||
820 | /* off-chip encoders require matching the exact encoder type */ | ||
821 | if (dcb->location != 0) | ||
822 | type |= dcb->extdev << 8; | ||
823 | |||
837 | return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); | 824 | return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); |
838 | } | 825 | } |
839 | 826 | ||
@@ -848,9 +835,11 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) | |||
848 | u32 ctrl = 0x00000000; | 835 | u32 ctrl = 0x00000000; |
849 | int i; | 836 | int i; |
850 | 837 | ||
838 | /* DAC */ | ||
851 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) | 839 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) |
852 | ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); | 840 | ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); |
853 | 841 | ||
842 | /* SOR */ | ||
854 | if (!(ctrl & (1 << head))) { | 843 | if (!(ctrl & (1 << head))) { |
855 | if (nv_device(priv)->chipset < 0x90 || | 844 | if (nv_device(priv)->chipset < 0x90 || |
856 | nv_device(priv)->chipset == 0x92 || | 845 | nv_device(priv)->chipset == 0x92 || |
@@ -865,6 +854,13 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) | |||
865 | } | 854 | } |
866 | } | 855 | } |
867 | 856 | ||
857 | /* PIOR */ | ||
858 | if (!(ctrl & (1 << head))) { | ||
859 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) | ||
860 | ctrl = nv_rd32(priv, 0x610b84 + (i * 8)); | ||
861 | i += 8; | ||
862 | } | ||
863 | |||
868 | if (!(ctrl & (1 << head))) | 864 | if (!(ctrl & (1 << head))) |
869 | return false; | 865 | return false; |
870 | i--; | 866 | i--; |
@@ -894,13 +890,15 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, | |||
894 | struct nvbios_outp info1; | 890 | struct nvbios_outp info1; |
895 | struct nvbios_ocfg info2; | 891 | struct nvbios_ocfg info2; |
896 | u8 ver, hdr, cnt, len; | 892 | u8 ver, hdr, cnt, len; |
897 | u16 data, conf; | ||
898 | u32 ctrl = 0x00000000; | 893 | u32 ctrl = 0x00000000; |
894 | u32 data, conf = ~0; | ||
899 | int i; | 895 | int i; |
900 | 896 | ||
897 | /* DAC */ | ||
901 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) | 898 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) |
902 | ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); | 899 | ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); |
903 | 900 | ||
901 | /* SOR */ | ||
904 | if (!(ctrl & (1 << head))) { | 902 | if (!(ctrl & (1 << head))) { |
905 | if (nv_device(priv)->chipset < 0x90 || | 903 | if (nv_device(priv)->chipset < 0x90 || |
906 | nv_device(priv)->chipset == 0x92 || | 904 | nv_device(priv)->chipset == 0x92 || |
@@ -915,34 +913,46 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, | |||
915 | } | 913 | } |
916 | } | 914 | } |
917 | 915 | ||
916 | /* PIOR */ | ||
917 | if (!(ctrl & (1 << head))) { | ||
918 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) | ||
919 | ctrl = nv_rd32(priv, 0x610b80 + (i * 8)); | ||
920 | i += 8; | ||
921 | } | ||
922 | |||
918 | if (!(ctrl & (1 << head))) | 923 | if (!(ctrl & (1 << head))) |
919 | return 0x0000; | 924 | return conf; |
920 | i--; | 925 | i--; |
921 | 926 | ||
922 | data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); | 927 | data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); |
923 | if (!data) | 928 | if (!data) |
924 | return 0x0000; | 929 | return conf; |
925 | 930 | ||
926 | switch (outp->type) { | 931 | if (outp->location == 0) { |
927 | case DCB_OUTPUT_TMDS: | 932 | switch (outp->type) { |
928 | conf = (ctrl & 0x00000f00) >> 8; | 933 | case DCB_OUTPUT_TMDS: |
929 | if (pclk >= 165000) | 934 | conf = (ctrl & 0x00000f00) >> 8; |
930 | conf |= 0x0100; | 935 | if (pclk >= 165000) |
931 | break; | 936 | conf |= 0x0100; |
932 | case DCB_OUTPUT_LVDS: | 937 | break; |
933 | conf = priv->sor.lvdsconf; | 938 | case DCB_OUTPUT_LVDS: |
934 | break; | 939 | conf = priv->sor.lvdsconf; |
935 | case DCB_OUTPUT_DP: | 940 | break; |
941 | case DCB_OUTPUT_DP: | ||
942 | conf = (ctrl & 0x00000f00) >> 8; | ||
943 | break; | ||
944 | case DCB_OUTPUT_ANALOG: | ||
945 | default: | ||
946 | conf = 0x00ff; | ||
947 | break; | ||
948 | } | ||
949 | } else { | ||
936 | conf = (ctrl & 0x00000f00) >> 8; | 950 | conf = (ctrl & 0x00000f00) >> 8; |
937 | break; | 951 | pclk = pclk / 2; |
938 | case DCB_OUTPUT_ANALOG: | ||
939 | default: | ||
940 | conf = 0x00ff; | ||
941 | break; | ||
942 | } | 952 | } |
943 | 953 | ||
944 | data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); | 954 | data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); |
945 | if (data) { | 955 | if (data && id < 0xff) { |
946 | data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); | 956 | data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); |
947 | if (data) { | 957 | if (data) { |
948 | struct nvbios_init init = { | 958 | struct nvbios_init init = { |
@@ -954,13 +964,11 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, | |||
954 | .execute = 1, | 964 | .execute = 1, |
955 | }; | 965 | }; |
956 | 966 | ||
957 | if (nvbios_exec(&init)) | 967 | nvbios_exec(&init); |
958 | return 0x0000; | ||
959 | return conf; | ||
960 | } | 968 | } |
961 | } | 969 | } |
962 | 970 | ||
963 | return 0x0000; | 971 | return conf; |
964 | } | 972 | } |
965 | 973 | ||
966 | static void | 974 | static void |
@@ -973,7 +981,6 @@ nv50_disp_intr_unk10(struct nv50_disp_priv *priv, u32 super) | |||
973 | exec_script(priv, head, 1); | 981 | exec_script(priv, head, 1); |
974 | } | 982 | } |
975 | 983 | ||
976 | nv_wr32(priv, 0x610024, 0x00000010); | ||
977 | nv_wr32(priv, 0x610030, 0x80000000); | 984 | nv_wr32(priv, 0x610030, 0x80000000); |
978 | } | 985 | } |
979 | 986 | ||
@@ -1088,7 +1095,6 @@ static void | |||
1088 | nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super) | 1095 | nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super) |
1089 | { | 1096 | { |
1090 | struct dcb_output outp; | 1097 | struct dcb_output outp; |
1091 | u32 addr, mask, data; | ||
1092 | int head; | 1098 | int head; |
1093 | 1099 | ||
1094 | /* finish detaching encoder? */ | 1100 | /* finish detaching encoder? */ |
@@ -1104,33 +1110,58 @@ nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super) | |||
1104 | struct nouveau_clock *clk = nouveau_clock(priv); | 1110 | struct nouveau_clock *clk = nouveau_clock(priv); |
1105 | clk->pll_set(clk, PLL_VPLL0 + head, pclk); | 1111 | clk->pll_set(clk, PLL_VPLL0 + head, pclk); |
1106 | } | 1112 | } |
1107 | |||
1108 | nv_mask(priv, 0x614200 + head * 0x800, 0x0000000f, 0x00000000); | ||
1109 | } | 1113 | } |
1110 | 1114 | ||
1111 | /* (re)attach the relevant OR to the head */ | 1115 | /* (re)attach the relevant OR to the head */ |
1112 | head = ffs((super & 0x00000180) >> 7) - 1; | 1116 | head = ffs((super & 0x00000180) >> 7) - 1; |
1113 | if (head >= 0) { | 1117 | if (head >= 0) { |
1114 | u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; | 1118 | u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; |
1115 | u32 conf = exec_clkcmp(priv, head, 0, pclk, &outp); | 1119 | u32 hval, hreg = 0x614200 + (head * 0x800); |
1116 | if (conf) { | 1120 | u32 oval, oreg; |
1117 | if (outp.type == DCB_OUTPUT_ANALOG) { | 1121 | u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp); |
1118 | addr = 0x614280 + (ffs(outp.or) - 1) * 0x800; | 1122 | if (conf != ~0) { |
1119 | mask = 0xffffffff; | 1123 | if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) { |
1120 | data = 0x00000000; | 1124 | u32 soff = (ffs(outp.or) - 1) * 0x08; |
1121 | } else { | 1125 | u32 ctrl = nv_rd32(priv, 0x610798 + soff); |
1126 | u32 datarate; | ||
1127 | |||
1128 | switch ((ctrl & 0x000f0000) >> 16) { | ||
1129 | case 6: datarate = pclk * 30 / 8; break; | ||
1130 | case 5: datarate = pclk * 24 / 8; break; | ||
1131 | case 2: | ||
1132 | default: | ||
1133 | datarate = pclk * 18 / 8; | ||
1134 | break; | ||
1135 | } | ||
1136 | |||
1137 | nouveau_dp_train(&priv->base, priv->sor.dp, | ||
1138 | &outp, head, datarate); | ||
1139 | } | ||
1140 | |||
1141 | exec_clkcmp(priv, head, 0, pclk, &outp); | ||
1142 | |||
1143 | if (!outp.location && outp.type == DCB_OUTPUT_ANALOG) { | ||
1144 | oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800; | ||
1145 | oval = 0x00000000; | ||
1146 | hval = 0x00000000; | ||
1147 | } else | ||
1148 | if (!outp.location) { | ||
1122 | if (outp.type == DCB_OUTPUT_DP) | 1149 | if (outp.type == DCB_OUTPUT_DP) |
1123 | nv50_disp_intr_unk20_dp(priv, &outp, pclk); | 1150 | nv50_disp_intr_unk20_dp(priv, &outp, pclk); |
1124 | addr = 0x614300 + (ffs(outp.or) - 1) * 0x800; | 1151 | oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800; |
1125 | mask = 0x00000707; | 1152 | oval = (conf & 0x0100) ? 0x0101 : 0x0000; |
1126 | data = (conf & 0x0100) ? 0x0101 : 0x0000; | 1153 | hval = 0x00000000; |
1154 | } else { | ||
1155 | oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800; | ||
1156 | oval = 0x00000001; | ||
1157 | hval = 0x00000001; | ||
1127 | } | 1158 | } |
1128 | 1159 | ||
1129 | nv_mask(priv, addr, mask, data); | 1160 | nv_mask(priv, hreg, 0x0000000f, hval); |
1161 | nv_mask(priv, oreg, 0x00000707, oval); | ||
1130 | } | 1162 | } |
1131 | } | 1163 | } |
1132 | 1164 | ||
1133 | nv_wr32(priv, 0x610024, 0x00000020); | ||
1134 | nv_wr32(priv, 0x610030, 0x80000000); | 1165 | nv_wr32(priv, 0x610030, 0x80000000); |
1135 | } | 1166 | } |
1136 | 1167 | ||
@@ -1163,28 +1194,47 @@ nv50_disp_intr_unk40(struct nv50_disp_priv *priv, u32 super) | |||
1163 | if (head >= 0) { | 1194 | if (head >= 0) { |
1164 | struct dcb_output outp; | 1195 | struct dcb_output outp; |
1165 | u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; | 1196 | u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; |
1166 | if (pclk && exec_clkcmp(priv, head, 1, pclk, &outp)) { | 1197 | if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) { |
1167 | if (outp.type == DCB_OUTPUT_TMDS) | 1198 | if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS) |
1168 | nv50_disp_intr_unk40_tmds(priv, &outp); | 1199 | nv50_disp_intr_unk40_tmds(priv, &outp); |
1200 | else | ||
1201 | if (outp.location == 1 && outp.type == DCB_OUTPUT_DP) { | ||
1202 | u32 soff = (ffs(outp.or) - 1) * 0x08; | ||
1203 | u32 ctrl = nv_rd32(priv, 0x610b84 + soff); | ||
1204 | u32 datarate; | ||
1205 | |||
1206 | switch ((ctrl & 0x000f0000) >> 16) { | ||
1207 | case 6: datarate = pclk * 30 / 8; break; | ||
1208 | case 5: datarate = pclk * 24 / 8; break; | ||
1209 | case 2: | ||
1210 | default: | ||
1211 | datarate = pclk * 18 / 8; | ||
1212 | break; | ||
1213 | } | ||
1214 | |||
1215 | nouveau_dp_train(&priv->base, priv->pior.dp, | ||
1216 | &outp, head, datarate); | ||
1217 | } | ||
1169 | } | 1218 | } |
1170 | } | 1219 | } |
1171 | 1220 | ||
1172 | nv_wr32(priv, 0x610024, 0x00000040); | ||
1173 | nv_wr32(priv, 0x610030, 0x80000000); | 1221 | nv_wr32(priv, 0x610030, 0x80000000); |
1174 | } | 1222 | } |
1175 | 1223 | ||
1176 | static void | 1224 | void |
1177 | nv50_disp_intr_super(struct nv50_disp_priv *priv, u32 intr1) | 1225 | nv50_disp_intr_supervisor(struct work_struct *work) |
1178 | { | 1226 | { |
1227 | struct nv50_disp_priv *priv = | ||
1228 | container_of(work, struct nv50_disp_priv, supervisor); | ||
1179 | u32 super = nv_rd32(priv, 0x610030); | 1229 | u32 super = nv_rd32(priv, 0x610030); |
1180 | 1230 | ||
1181 | nv_debug(priv, "supervisor 0x%08x 0x%08x\n", intr1, super); | 1231 | nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super); |
1182 | 1232 | ||
1183 | if (intr1 & 0x00000010) | 1233 | if (priv->super & 0x00000010) |
1184 | nv50_disp_intr_unk10(priv, super); | 1234 | nv50_disp_intr_unk10(priv, super); |
1185 | if (intr1 & 0x00000020) | 1235 | if (priv->super & 0x00000020) |
1186 | nv50_disp_intr_unk20(priv, super); | 1236 | nv50_disp_intr_unk20(priv, super); |
1187 | if (intr1 & 0x00000040) | 1237 | if (priv->super & 0x00000040) |
1188 | nv50_disp_intr_unk40(priv, super); | 1238 | nv50_disp_intr_unk40(priv, super); |
1189 | } | 1239 | } |
1190 | 1240 | ||
@@ -1201,19 +1251,21 @@ nv50_disp_intr(struct nouveau_subdev *subdev) | |||
1201 | } | 1251 | } |
1202 | 1252 | ||
1203 | if (intr1 & 0x00000004) { | 1253 | if (intr1 & 0x00000004) { |
1204 | nv50_disp_intr_vblank(priv, 0); | 1254 | nouveau_event_trigger(priv->base.vblank, 0); |
1205 | nv_wr32(priv, 0x610024, 0x00000004); | 1255 | nv_wr32(priv, 0x610024, 0x00000004); |
1206 | intr1 &= ~0x00000004; | 1256 | intr1 &= ~0x00000004; |
1207 | } | 1257 | } |
1208 | 1258 | ||
1209 | if (intr1 & 0x00000008) { | 1259 | if (intr1 & 0x00000008) { |
1210 | nv50_disp_intr_vblank(priv, 1); | 1260 | nouveau_event_trigger(priv->base.vblank, 1); |
1211 | nv_wr32(priv, 0x610024, 0x00000008); | 1261 | nv_wr32(priv, 0x610024, 0x00000008); |
1212 | intr1 &= ~0x00000008; | 1262 | intr1 &= ~0x00000008; |
1213 | } | 1263 | } |
1214 | 1264 | ||
1215 | if (intr1 & 0x00000070) { | 1265 | if (intr1 & 0x00000070) { |
1216 | nv50_disp_intr_super(priv, intr1); | 1266 | priv->super = (intr1 & 0x00000070); |
1267 | schedule_work(&priv->supervisor); | ||
1268 | nv_wr32(priv, 0x610024, priv->super); | ||
1217 | intr1 &= ~0x00000070; | 1269 | intr1 &= ~0x00000070; |
1218 | } | 1270 | } |
1219 | } | 1271 | } |
@@ -1226,7 +1278,7 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
1226 | struct nv50_disp_priv *priv; | 1278 | struct nv50_disp_priv *priv; |
1227 | int ret; | 1279 | int ret; |
1228 | 1280 | ||
1229 | ret = nouveau_disp_create(parent, engine, oclass, "PDISP", | 1281 | ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP", |
1230 | "display", &priv); | 1282 | "display", &priv); |
1231 | *pobject = nv_object(priv); | 1283 | *pobject = nv_object(priv); |
1232 | if (ret) | 1284 | if (ret) |
@@ -1235,16 +1287,17 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
1235 | nv_engine(priv)->sclass = nv50_disp_base_oclass; | 1287 | nv_engine(priv)->sclass = nv50_disp_base_oclass; |
1236 | nv_engine(priv)->cclass = &nv50_disp_cclass; | 1288 | nv_engine(priv)->cclass = &nv50_disp_cclass; |
1237 | nv_subdev(priv)->intr = nv50_disp_intr; | 1289 | nv_subdev(priv)->intr = nv50_disp_intr; |
1290 | INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); | ||
1238 | priv->sclass = nv50_disp_sclass; | 1291 | priv->sclass = nv50_disp_sclass; |
1239 | priv->head.nr = 2; | 1292 | priv->head.nr = 2; |
1240 | priv->dac.nr = 3; | 1293 | priv->dac.nr = 3; |
1241 | priv->sor.nr = 2; | 1294 | priv->sor.nr = 2; |
1295 | priv->pior.nr = 3; | ||
1242 | priv->dac.power = nv50_dac_power; | 1296 | priv->dac.power = nv50_dac_power; |
1243 | priv->dac.sense = nv50_dac_sense; | 1297 | priv->dac.sense = nv50_dac_sense; |
1244 | priv->sor.power = nv50_sor_power; | 1298 | priv->sor.power = nv50_sor_power; |
1245 | 1299 | priv->pior.power = nv50_pior_power; | |
1246 | INIT_LIST_HEAD(&priv->base.vblank.list); | 1300 | priv->pior.dp = &nv50_pior_dp_func; |
1247 | spin_lock_init(&priv->base.vblank.lock); | ||
1248 | return 0; | 1301 | return 0; |
1249 | } | 1302 | } |
1250 | 1303 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h index a6bb931450f1..1ae6ceb56704 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h | |||
@@ -3,16 +3,22 @@ | |||
3 | 3 | ||
4 | #include <core/parent.h> | 4 | #include <core/parent.h> |
5 | #include <core/namedb.h> | 5 | #include <core/namedb.h> |
6 | #include <core/engctx.h> | ||
6 | #include <core/ramht.h> | 7 | #include <core/ramht.h> |
8 | #include <core/event.h> | ||
7 | 9 | ||
8 | #include <engine/dmaobj.h> | 10 | #include <engine/dmaobj.h> |
9 | #include <engine/disp.h> | 11 | #include <engine/disp.h> |
10 | 12 | ||
11 | struct dcb_output; | 13 | #include "dport.h" |
12 | 14 | ||
13 | struct nv50_disp_priv { | 15 | struct nv50_disp_priv { |
14 | struct nouveau_disp base; | 16 | struct nouveau_disp base; |
15 | struct nouveau_oclass *sclass; | 17 | struct nouveau_oclass *sclass; |
18 | |||
19 | struct work_struct supervisor; | ||
20 | u32 super; | ||
21 | |||
16 | struct { | 22 | struct { |
17 | int nr; | 23 | int nr; |
18 | } head; | 24 | } head; |
@@ -26,23 +32,15 @@ struct nv50_disp_priv { | |||
26 | int (*power)(struct nv50_disp_priv *, int sor, u32 data); | 32 | int (*power)(struct nv50_disp_priv *, int sor, u32 data); |
27 | int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32); | 33 | int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32); |
28 | int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32); | 34 | int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32); |
29 | int (*dp_train_init)(struct nv50_disp_priv *, int sor, int link, | ||
30 | int head, u16 type, u16 mask, u32 data, | ||
31 | struct dcb_output *); | ||
32 | int (*dp_train_fini)(struct nv50_disp_priv *, int sor, int link, | ||
33 | int head, u16 type, u16 mask, u32 data, | ||
34 | struct dcb_output *); | ||
35 | int (*dp_train)(struct nv50_disp_priv *, int sor, int link, | ||
36 | u16 type, u16 mask, u32 data, | ||
37 | struct dcb_output *); | ||
38 | int (*dp_lnkctl)(struct nv50_disp_priv *, int sor, int link, | ||
39 | int head, u16 type, u16 mask, u32 data, | ||
40 | struct dcb_output *); | ||
41 | int (*dp_drvctl)(struct nv50_disp_priv *, int sor, int link, | ||
42 | int lane, u16 type, u16 mask, u32 data, | ||
43 | struct dcb_output *); | ||
44 | u32 lvdsconf; | 35 | u32 lvdsconf; |
36 | const struct nouveau_dp_func *dp; | ||
45 | } sor; | 37 | } sor; |
38 | struct { | ||
39 | int nr; | ||
40 | int (*power)(struct nv50_disp_priv *, int ext, u32 data); | ||
41 | u8 type[3]; | ||
42 | const struct nouveau_dp_func *dp; | ||
43 | } pior; | ||
46 | }; | 44 | }; |
47 | 45 | ||
48 | #define DAC_MTHD(n) (n), (n) + 0x03 | 46 | #define DAC_MTHD(n) (n), (n) + 0x03 |
@@ -81,6 +79,11 @@ int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32, | |||
81 | int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32, | 79 | int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32, |
82 | struct dcb_output *); | 80 | struct dcb_output *); |
83 | 81 | ||
82 | #define PIOR_MTHD(n) (n), (n) + 0x03 | ||
83 | |||
84 | int nv50_pior_mthd(struct nouveau_object *, u32, void *, u32); | ||
85 | int nv50_pior_power(struct nv50_disp_priv *, int, u32); | ||
86 | |||
84 | struct nv50_disp_base { | 87 | struct nv50_disp_base { |
85 | struct nouveau_parent base; | 88 | struct nouveau_parent base; |
86 | struct nouveau_ramht *ramht; | 89 | struct nouveau_ramht *ramht; |
@@ -124,6 +127,7 @@ extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs; | |||
124 | extern struct nouveau_ofuncs nv50_disp_curs_ofuncs; | 127 | extern struct nouveau_ofuncs nv50_disp_curs_ofuncs; |
125 | extern struct nouveau_ofuncs nv50_disp_base_ofuncs; | 128 | extern struct nouveau_ofuncs nv50_disp_base_ofuncs; |
126 | extern struct nouveau_oclass nv50_disp_cclass; | 129 | extern struct nouveau_oclass nv50_disp_cclass; |
130 | void nv50_disp_intr_supervisor(struct work_struct *); | ||
127 | void nv50_disp_intr(struct nouveau_subdev *); | 131 | void nv50_disp_intr(struct nouveau_subdev *); |
128 | 132 | ||
129 | extern struct nouveau_omthds nv84_disp_base_omthds[]; | 133 | extern struct nouveau_omthds nv84_disp_base_omthds[]; |
@@ -137,6 +141,7 @@ extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs; | |||
137 | extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs; | 141 | extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs; |
138 | extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; | 142 | extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; |
139 | extern struct nouveau_oclass nvd0_disp_cclass; | 143 | extern struct nouveau_oclass nvd0_disp_cclass; |
144 | void nvd0_disp_intr_supervisor(struct work_struct *); | ||
140 | void nvd0_disp_intr(struct nouveau_subdev *); | 145 | void nvd0_disp_intr(struct nouveau_subdev *); |
141 | 146 | ||
142 | #endif | 147 | #endif |
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c index fc84eacdfbec..d8c74c0883a1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c | |||
@@ -46,6 +46,9 @@ nv84_disp_base_omthds[] = { | |||
46 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, | 46 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, |
47 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, | 47 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, |
48 | { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, | 48 | { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, |
49 | { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, | ||
50 | { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, | ||
51 | { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd }, | ||
49 | {}, | 52 | {}, |
50 | }; | 53 | }; |
51 | 54 | ||
@@ -63,7 +66,7 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
63 | struct nv50_disp_priv *priv; | 66 | struct nv50_disp_priv *priv; |
64 | int ret; | 67 | int ret; |
65 | 68 | ||
66 | ret = nouveau_disp_create(parent, engine, oclass, "PDISP", | 69 | ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP", |
67 | "display", &priv); | 70 | "display", &priv); |
68 | *pobject = nv_object(priv); | 71 | *pobject = nv_object(priv); |
69 | if (ret) | 72 | if (ret) |
@@ -72,17 +75,18 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
72 | nv_engine(priv)->sclass = nv84_disp_base_oclass; | 75 | nv_engine(priv)->sclass = nv84_disp_base_oclass; |
73 | nv_engine(priv)->cclass = &nv50_disp_cclass; | 76 | nv_engine(priv)->cclass = &nv50_disp_cclass; |
74 | nv_subdev(priv)->intr = nv50_disp_intr; | 77 | nv_subdev(priv)->intr = nv50_disp_intr; |
78 | INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); | ||
75 | priv->sclass = nv84_disp_sclass; | 79 | priv->sclass = nv84_disp_sclass; |
76 | priv->head.nr = 2; | 80 | priv->head.nr = 2; |
77 | priv->dac.nr = 3; | 81 | priv->dac.nr = 3; |
78 | priv->sor.nr = 2; | 82 | priv->sor.nr = 2; |
83 | priv->pior.nr = 3; | ||
79 | priv->dac.power = nv50_dac_power; | 84 | priv->dac.power = nv50_dac_power; |
80 | priv->dac.sense = nv50_dac_sense; | 85 | priv->dac.sense = nv50_dac_sense; |
81 | priv->sor.power = nv50_sor_power; | 86 | priv->sor.power = nv50_sor_power; |
82 | priv->sor.hdmi = nv84_hdmi_ctrl; | 87 | priv->sor.hdmi = nv84_hdmi_ctrl; |
83 | 88 | priv->pior.power = nv50_pior_power; | |
84 | INIT_LIST_HEAD(&priv->base.vblank.list); | 89 | priv->pior.dp = &nv50_pior_dp_func; |
85 | spin_lock_init(&priv->base.vblank.lock); | ||
86 | return 0; | 90 | return 0; |
87 | } | 91 | } |
88 | 92 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c index ba9dfd4669a2..a66f949c1f84 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c | |||
@@ -44,14 +44,11 @@ nv94_disp_base_omthds[] = { | |||
44 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, | 44 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, |
45 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, | 45 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, |
46 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, | 46 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, |
47 | { SOR_MTHD(NV94_DISP_SOR_DP_TRAIN) , nv50_sor_mthd }, | ||
48 | { SOR_MTHD(NV94_DISP_SOR_DP_LNKCTL) , nv50_sor_mthd }, | ||
49 | { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(0)), nv50_sor_mthd }, | ||
50 | { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(1)), nv50_sor_mthd }, | ||
51 | { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(2)), nv50_sor_mthd }, | ||
52 | { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(3)), nv50_sor_mthd }, | ||
53 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, | 47 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, |
54 | { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, | 48 | { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, |
49 | { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, | ||
50 | { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, | ||
51 | { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd }, | ||
55 | {}, | 52 | {}, |
56 | }; | 53 | }; |
57 | 54 | ||
@@ -69,7 +66,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
69 | struct nv50_disp_priv *priv; | 66 | struct nv50_disp_priv *priv; |
70 | int ret; | 67 | int ret; |
71 | 68 | ||
72 | ret = nouveau_disp_create(parent, engine, oclass, "PDISP", | 69 | ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP", |
73 | "display", &priv); | 70 | "display", &priv); |
74 | *pobject = nv_object(priv); | 71 | *pobject = nv_object(priv); |
75 | if (ret) | 72 | if (ret) |
@@ -78,22 +75,19 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
78 | nv_engine(priv)->sclass = nv94_disp_base_oclass; | 75 | nv_engine(priv)->sclass = nv94_disp_base_oclass; |
79 | nv_engine(priv)->cclass = &nv50_disp_cclass; | 76 | nv_engine(priv)->cclass = &nv50_disp_cclass; |
80 | nv_subdev(priv)->intr = nv50_disp_intr; | 77 | nv_subdev(priv)->intr = nv50_disp_intr; |
78 | INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); | ||
81 | priv->sclass = nv94_disp_sclass; | 79 | priv->sclass = nv94_disp_sclass; |
82 | priv->head.nr = 2; | 80 | priv->head.nr = 2; |
83 | priv->dac.nr = 3; | 81 | priv->dac.nr = 3; |
84 | priv->sor.nr = 4; | 82 | priv->sor.nr = 4; |
83 | priv->pior.nr = 3; | ||
85 | priv->dac.power = nv50_dac_power; | 84 | priv->dac.power = nv50_dac_power; |
86 | priv->dac.sense = nv50_dac_sense; | 85 | priv->dac.sense = nv50_dac_sense; |
87 | priv->sor.power = nv50_sor_power; | 86 | priv->sor.power = nv50_sor_power; |
88 | priv->sor.hdmi = nv84_hdmi_ctrl; | 87 | priv->sor.hdmi = nv84_hdmi_ctrl; |
89 | priv->sor.dp_train = nv94_sor_dp_train; | 88 | priv->sor.dp = &nv94_sor_dp_func; |
90 | priv->sor.dp_train_init = nv94_sor_dp_train_init; | 89 | priv->pior.power = nv50_pior_power; |
91 | priv->sor.dp_train_fini = nv94_sor_dp_train_fini; | 90 | priv->pior.dp = &nv50_pior_dp_func; |
92 | priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl; | ||
93 | priv->sor.dp_drvctl = nv94_sor_dp_drvctl; | ||
94 | |||
95 | INIT_LIST_HEAD(&priv->base.vblank.list); | ||
96 | spin_lock_init(&priv->base.vblank.lock); | ||
97 | return 0; | 91 | return 0; |
98 | } | 92 | } |
99 | 93 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c index 5d63902cdeda..6cf8eefac368 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c | |||
@@ -53,7 +53,7 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
53 | struct nv50_disp_priv *priv; | 53 | struct nv50_disp_priv *priv; |
54 | int ret; | 54 | int ret; |
55 | 55 | ||
56 | ret = nouveau_disp_create(parent, engine, oclass, "PDISP", | 56 | ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP", |
57 | "display", &priv); | 57 | "display", &priv); |
58 | *pobject = nv_object(priv); | 58 | *pobject = nv_object(priv); |
59 | if (ret) | 59 | if (ret) |
@@ -62,17 +62,18 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
62 | nv_engine(priv)->sclass = nva0_disp_base_oclass; | 62 | nv_engine(priv)->sclass = nva0_disp_base_oclass; |
63 | nv_engine(priv)->cclass = &nv50_disp_cclass; | 63 | nv_engine(priv)->cclass = &nv50_disp_cclass; |
64 | nv_subdev(priv)->intr = nv50_disp_intr; | 64 | nv_subdev(priv)->intr = nv50_disp_intr; |
65 | INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); | ||
65 | priv->sclass = nva0_disp_sclass; | 66 | priv->sclass = nva0_disp_sclass; |
66 | priv->head.nr = 2; | 67 | priv->head.nr = 2; |
67 | priv->dac.nr = 3; | 68 | priv->dac.nr = 3; |
68 | priv->sor.nr = 2; | 69 | priv->sor.nr = 2; |
70 | priv->pior.nr = 3; | ||
69 | priv->dac.power = nv50_dac_power; | 71 | priv->dac.power = nv50_dac_power; |
70 | priv->dac.sense = nv50_dac_sense; | 72 | priv->dac.sense = nv50_dac_sense; |
71 | priv->sor.power = nv50_sor_power; | 73 | priv->sor.power = nv50_sor_power; |
72 | priv->sor.hdmi = nv84_hdmi_ctrl; | 74 | priv->sor.hdmi = nv84_hdmi_ctrl; |
73 | 75 | priv->pior.power = nv50_pior_power; | |
74 | INIT_LIST_HEAD(&priv->base.vblank.list); | 76 | priv->pior.dp = &nv50_pior_dp_func; |
75 | spin_lock_init(&priv->base.vblank.lock); | ||
76 | return 0; | 77 | return 0; |
77 | } | 78 | } |
78 | 79 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c index e9192ca389fa..b75413169eae 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c | |||
@@ -45,14 +45,11 @@ nva3_disp_base_omthds[] = { | |||
45 | { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, | 45 | { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, |
46 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, | 46 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, |
47 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, | 47 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, |
48 | { SOR_MTHD(NV94_DISP_SOR_DP_TRAIN) , nv50_sor_mthd }, | ||
49 | { SOR_MTHD(NV94_DISP_SOR_DP_LNKCTL) , nv50_sor_mthd }, | ||
50 | { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(0)), nv50_sor_mthd }, | ||
51 | { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(1)), nv50_sor_mthd }, | ||
52 | { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(2)), nv50_sor_mthd }, | ||
53 | { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(3)), nv50_sor_mthd }, | ||
54 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, | 48 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, |
55 | { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, | 49 | { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, |
50 | { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, | ||
51 | { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, | ||
52 | { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd }, | ||
56 | {}, | 53 | {}, |
57 | }; | 54 | }; |
58 | 55 | ||
@@ -70,7 +67,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
70 | struct nv50_disp_priv *priv; | 67 | struct nv50_disp_priv *priv; |
71 | int ret; | 68 | int ret; |
72 | 69 | ||
73 | ret = nouveau_disp_create(parent, engine, oclass, "PDISP", | 70 | ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP", |
74 | "display", &priv); | 71 | "display", &priv); |
75 | *pobject = nv_object(priv); | 72 | *pobject = nv_object(priv); |
76 | if (ret) | 73 | if (ret) |
@@ -79,23 +76,20 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
79 | nv_engine(priv)->sclass = nva3_disp_base_oclass; | 76 | nv_engine(priv)->sclass = nva3_disp_base_oclass; |
80 | nv_engine(priv)->cclass = &nv50_disp_cclass; | 77 | nv_engine(priv)->cclass = &nv50_disp_cclass; |
81 | nv_subdev(priv)->intr = nv50_disp_intr; | 78 | nv_subdev(priv)->intr = nv50_disp_intr; |
79 | INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); | ||
82 | priv->sclass = nva3_disp_sclass; | 80 | priv->sclass = nva3_disp_sclass; |
83 | priv->head.nr = 2; | 81 | priv->head.nr = 2; |
84 | priv->dac.nr = 3; | 82 | priv->dac.nr = 3; |
85 | priv->sor.nr = 4; | 83 | priv->sor.nr = 4; |
84 | priv->pior.nr = 3; | ||
86 | priv->dac.power = nv50_dac_power; | 85 | priv->dac.power = nv50_dac_power; |
87 | priv->dac.sense = nv50_dac_sense; | 86 | priv->dac.sense = nv50_dac_sense; |
88 | priv->sor.power = nv50_sor_power; | 87 | priv->sor.power = nv50_sor_power; |
89 | priv->sor.hda_eld = nva3_hda_eld; | 88 | priv->sor.hda_eld = nva3_hda_eld; |
90 | priv->sor.hdmi = nva3_hdmi_ctrl; | 89 | priv->sor.hdmi = nva3_hdmi_ctrl; |
91 | priv->sor.dp_train = nv94_sor_dp_train; | 90 | priv->sor.dp = &nv94_sor_dp_func; |
92 | priv->sor.dp_train_init = nv94_sor_dp_train_init; | 91 | priv->pior.power = nv50_pior_power; |
93 | priv->sor.dp_train_fini = nv94_sor_dp_train_fini; | 92 | priv->pior.dp = &nv50_pior_dp_func; |
94 | priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl; | ||
95 | priv->sor.dp_drvctl = nv94_sor_dp_drvctl; | ||
96 | |||
97 | INIT_LIST_HEAD(&priv->base.vblank.list); | ||
98 | spin_lock_init(&priv->base.vblank.lock); | ||
99 | return 0; | 93 | return 0; |
100 | } | 94 | } |
101 | 95 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index 9e38ebff5fb3..7106a72e611e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c | |||
@@ -27,12 +27,10 @@ | |||
27 | #include <core/handle.h> | 27 | #include <core/handle.h> |
28 | #include <core/class.h> | 28 | #include <core/class.h> |
29 | 29 | ||
30 | #include <engine/software.h> | ||
31 | #include <engine/disp.h> | 30 | #include <engine/disp.h> |
32 | 31 | ||
33 | #include <subdev/timer.h> | 32 | #include <subdev/timer.h> |
34 | #include <subdev/fb.h> | 33 | #include <subdev/fb.h> |
35 | #include <subdev/bar.h> | ||
36 | #include <subdev/clock.h> | 34 | #include <subdev/clock.h> |
37 | 35 | ||
38 | #include <subdev/bios.h> | 36 | #include <subdev/bios.h> |
@@ -230,7 +228,7 @@ nvd0_disp_sync_ctor(struct nouveau_object *parent, | |||
230 | struct nv50_disp_dmac *dmac; | 228 | struct nv50_disp_dmac *dmac; |
231 | int ret; | 229 | int ret; |
232 | 230 | ||
233 | if (size < sizeof(*data) || args->head >= priv->head.nr) | 231 | if (size < sizeof(*args) || args->head >= priv->head.nr) |
234 | return -EINVAL; | 232 | return -EINVAL; |
235 | 233 | ||
236 | ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, | 234 | ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, |
@@ -270,7 +268,7 @@ nvd0_disp_ovly_ctor(struct nouveau_object *parent, | |||
270 | struct nv50_disp_dmac *dmac; | 268 | struct nv50_disp_dmac *dmac; |
271 | int ret; | 269 | int ret; |
272 | 270 | ||
273 | if (size < sizeof(*data) || args->head >= priv->head.nr) | 271 | if (size < sizeof(*args) || args->head >= priv->head.nr) |
274 | return -EINVAL; | 272 | return -EINVAL; |
275 | 273 | ||
276 | ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, | 274 | ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, |
@@ -443,6 +441,18 @@ nvd0_disp_curs_ofuncs = { | |||
443 | * Base display object | 441 | * Base display object |
444 | ******************************************************************************/ | 442 | ******************************************************************************/ |
445 | 443 | ||
444 | static void | ||
445 | nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head) | ||
446 | { | ||
447 | nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); | ||
448 | } | ||
449 | |||
450 | static void | ||
451 | nvd0_disp_base_vblank_disable(struct nouveau_event *event, int head) | ||
452 | { | ||
453 | nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); | ||
454 | } | ||
455 | |||
446 | static int | 456 | static int |
447 | nvd0_disp_base_ctor(struct nouveau_object *parent, | 457 | nvd0_disp_base_ctor(struct nouveau_object *parent, |
448 | struct nouveau_object *engine, | 458 | struct nouveau_object *engine, |
@@ -459,6 +469,10 @@ nvd0_disp_base_ctor(struct nouveau_object *parent, | |||
459 | if (ret) | 469 | if (ret) |
460 | return ret; | 470 | return ret; |
461 | 471 | ||
472 | priv->base.vblank->priv = priv; | ||
473 | priv->base.vblank->enable = nvd0_disp_base_vblank_enable; | ||
474 | priv->base.vblank->disable = nvd0_disp_base_vblank_disable; | ||
475 | |||
462 | return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht); | 476 | return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht); |
463 | } | 477 | } |
464 | 478 | ||
@@ -636,20 +650,19 @@ exec_script(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, int id) | |||
636 | 650 | ||
637 | static u32 | 651 | static u32 |
638 | exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp, | 652 | exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp, |
639 | u32 ctrl, int id, u32 pclk) | 653 | u32 ctrl, int id, u32 pclk, struct dcb_output *dcb) |
640 | { | 654 | { |
641 | struct nouveau_bios *bios = nouveau_bios(priv); | 655 | struct nouveau_bios *bios = nouveau_bios(priv); |
642 | struct nvbios_outp info1; | 656 | struct nvbios_outp info1; |
643 | struct nvbios_ocfg info2; | 657 | struct nvbios_ocfg info2; |
644 | struct dcb_output dcb; | ||
645 | u8 ver, hdr, cnt, len; | 658 | u8 ver, hdr, cnt, len; |
646 | u16 data, conf; | 659 | u32 data, conf = ~0; |
647 | 660 | ||
648 | data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info1); | 661 | data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1); |
649 | if (data == 0x0000) | 662 | if (data == 0x0000) |
650 | return false; | 663 | return conf; |
651 | 664 | ||
652 | switch (dcb.type) { | 665 | switch (dcb->type) { |
653 | case DCB_OUTPUT_TMDS: | 666 | case DCB_OUTPUT_TMDS: |
654 | conf = (ctrl & 0x00000f00) >> 8; | 667 | conf = (ctrl & 0x00000f00) >> 8; |
655 | if (pclk >= 165000) | 668 | if (pclk >= 165000) |
@@ -668,25 +681,23 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp, | |||
668 | } | 681 | } |
669 | 682 | ||
670 | data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); | 683 | data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); |
671 | if (data) { | 684 | if (data && id < 0xff) { |
672 | data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); | 685 | data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); |
673 | if (data) { | 686 | if (data) { |
674 | struct nvbios_init init = { | 687 | struct nvbios_init init = { |
675 | .subdev = nv_subdev(priv), | 688 | .subdev = nv_subdev(priv), |
676 | .bios = bios, | 689 | .bios = bios, |
677 | .offset = data, | 690 | .offset = data, |
678 | .outp = &dcb, | 691 | .outp = dcb, |
679 | .crtc = head, | 692 | .crtc = head, |
680 | .execute = 1, | 693 | .execute = 1, |
681 | }; | 694 | }; |
682 | 695 | ||
683 | if (nvbios_exec(&init)) | 696 | nvbios_exec(&init); |
684 | return 0x0000; | ||
685 | return conf; | ||
686 | } | 697 | } |
687 | } | 698 | } |
688 | 699 | ||
689 | return 0x0000; | 700 | return conf; |
690 | } | 701 | } |
691 | 702 | ||
692 | static void | 703 | static void |
@@ -752,6 +763,7 @@ nvd0_display_unk2_calc_tu(struct nv50_disp_priv *priv, int head, int or) | |||
752 | static void | 763 | static void |
753 | nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) | 764 | nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) |
754 | { | 765 | { |
766 | struct dcb_output outp; | ||
755 | u32 pclk; | 767 | u32 pclk; |
756 | int i; | 768 | int i; |
757 | 769 | ||
@@ -771,10 +783,29 @@ nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) | |||
771 | nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000); | 783 | nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000); |
772 | 784 | ||
773 | for (i = 0; mask && i < 8; i++) { | 785 | for (i = 0; mask && i < 8; i++) { |
774 | u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20)), cfg; | 786 | u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20)); |
775 | if (mcp & (1 << head)) { | 787 | if (mcp & (1 << head)) { |
776 | if ((cfg = exec_clkcmp(priv, head, i, mcp, 0, pclk))) { | 788 | u32 cfg = exec_clkcmp(priv, head, i, mcp, 0xff, pclk, &outp); |
789 | if (cfg != ~0) { | ||
777 | u32 addr, mask, data = 0x00000000; | 790 | u32 addr, mask, data = 0x00000000; |
791 | |||
792 | if (outp.type == DCB_OUTPUT_DP) { | ||
793 | switch ((mcp & 0x000f0000) >> 16) { | ||
794 | case 6: pclk = pclk * 30 / 8; break; | ||
795 | case 5: pclk = pclk * 24 / 8; break; | ||
796 | case 2: | ||
797 | default: | ||
798 | pclk = pclk * 18 / 8; | ||
799 | break; | ||
800 | } | ||
801 | |||
802 | nouveau_dp_train(&priv->base, | ||
803 | priv->sor.dp, | ||
804 | &outp, head, pclk); | ||
805 | } | ||
806 | |||
807 | exec_clkcmp(priv, head, i, mcp, 0, pclk, &outp); | ||
808 | |||
778 | if (i < 4) { | 809 | if (i < 4) { |
779 | addr = 0x612280 + ((i - 0) * 0x800); | 810 | addr = 0x612280 + ((i - 0) * 0x800); |
780 | mask = 0xffffffff; | 811 | mask = 0xffffffff; |
@@ -807,6 +838,7 @@ nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) | |||
807 | static void | 838 | static void |
808 | nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) | 839 | nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) |
809 | { | 840 | { |
841 | struct dcb_output outp; | ||
810 | int pclk, i; | 842 | int pclk, i; |
811 | 843 | ||
812 | pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; | 844 | pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; |
@@ -814,7 +846,7 @@ nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) | |||
814 | for (i = 0; mask && i < 8; i++) { | 846 | for (i = 0; mask && i < 8; i++) { |
815 | u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20)); | 847 | u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20)); |
816 | if (mcp & (1 << head)) | 848 | if (mcp & (1 << head)) |
817 | exec_clkcmp(priv, head, i, mcp, 1, pclk); | 849 | exec_clkcmp(priv, head, i, mcp, 1, pclk, &outp); |
818 | } | 850 | } |
819 | 851 | ||
820 | nv_wr32(priv, 0x6101d4, 0x00000000); | 852 | nv_wr32(priv, 0x6101d4, 0x00000000); |
@@ -822,33 +854,24 @@ nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) | |||
822 | nv_wr32(priv, 0x6101d0, 0x80000000); | 854 | nv_wr32(priv, 0x6101d0, 0x80000000); |
823 | } | 855 | } |
824 | 856 | ||
825 | static void | 857 | void |
826 | nvd0_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) | 858 | nvd0_disp_intr_supervisor(struct work_struct *work) |
827 | { | 859 | { |
828 | struct nouveau_bar *bar = nouveau_bar(priv); | 860 | struct nv50_disp_priv *priv = |
829 | struct nouveau_disp *disp = &priv->base; | 861 | container_of(work, struct nv50_disp_priv, supervisor); |
830 | struct nouveau_software_chan *chan, *temp; | 862 | u32 mask = 0, head = ~0; |
831 | unsigned long flags; | ||
832 | |||
833 | spin_lock_irqsave(&disp->vblank.lock, flags); | ||
834 | list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) { | ||
835 | if (chan->vblank.crtc != crtc) | ||
836 | continue; | ||
837 | |||
838 | nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); | ||
839 | bar->flush(bar); | ||
840 | nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset)); | ||
841 | nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset)); | ||
842 | nv_wr32(priv, 0x060014, chan->vblank.value); | ||
843 | |||
844 | list_del(&chan->vblank.head); | ||
845 | if (disp->vblank.put) | ||
846 | disp->vblank.put(disp->vblank.data, crtc); | ||
847 | } | ||
848 | spin_unlock_irqrestore(&disp->vblank.lock, flags); | ||
849 | 863 | ||
850 | if (disp->vblank.notify) | 864 | while (!mask && ++head < priv->head.nr) |
851 | disp->vblank.notify(disp->vblank.data, crtc); | 865 | mask = nv_rd32(priv, 0x6101d4 + (head * 0x800)); |
866 | |||
867 | nv_debug(priv, "supervisor %08x %08x %d\n", priv->super, mask, head); | ||
868 | |||
869 | if (priv->super & 0x00000001) | ||
870 | nvd0_display_unk1_handler(priv, head, mask); | ||
871 | if (priv->super & 0x00000002) | ||
872 | nvd0_display_unk2_handler(priv, head, mask); | ||
873 | if (priv->super & 0x00000004) | ||
874 | nvd0_display_unk4_handler(priv, head, mask); | ||
852 | } | 875 | } |
853 | 876 | ||
854 | void | 877 | void |
@@ -884,27 +907,11 @@ nvd0_disp_intr(struct nouveau_subdev *subdev) | |||
884 | 907 | ||
885 | if (intr & 0x00100000) { | 908 | if (intr & 0x00100000) { |
886 | u32 stat = nv_rd32(priv, 0x6100ac); | 909 | u32 stat = nv_rd32(priv, 0x6100ac); |
887 | u32 mask = 0, crtc = ~0; | 910 | if (stat & 0x00000007) { |
888 | 911 | priv->super = (stat & 0x00000007); | |
889 | while (!mask && ++crtc < priv->head.nr) | 912 | schedule_work(&priv->supervisor); |
890 | mask = nv_rd32(priv, 0x6101d4 + (crtc * 0x800)); | 913 | nv_wr32(priv, 0x6100ac, priv->super); |
891 | 914 | stat &= ~0x00000007; | |
892 | if (stat & 0x00000001) { | ||
893 | nv_wr32(priv, 0x6100ac, 0x00000001); | ||
894 | nvd0_display_unk1_handler(priv, crtc, mask); | ||
895 | stat &= ~0x00000001; | ||
896 | } | ||
897 | |||
898 | if (stat & 0x00000002) { | ||
899 | nv_wr32(priv, 0x6100ac, 0x00000002); | ||
900 | nvd0_display_unk2_handler(priv, crtc, mask); | ||
901 | stat &= ~0x00000002; | ||
902 | } | ||
903 | |||
904 | if (stat & 0x00000004) { | ||
905 | nv_wr32(priv, 0x6100ac, 0x00000004); | ||
906 | nvd0_display_unk4_handler(priv, crtc, mask); | ||
907 | stat &= ~0x00000004; | ||
908 | } | 915 | } |
909 | 916 | ||
910 | if (stat) { | 917 | if (stat) { |
@@ -920,7 +927,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev) | |||
920 | if (mask & intr) { | 927 | if (mask & intr) { |
921 | u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); | 928 | u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); |
922 | if (stat & 0x00000001) | 929 | if (stat & 0x00000001) |
923 | nvd0_disp_intr_vblank(priv, i); | 930 | nouveau_event_trigger(priv->base.vblank, i); |
924 | nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); | 931 | nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); |
925 | nv_rd32(priv, 0x6100c0 + (i * 0x800)); | 932 | nv_rd32(priv, 0x6100c0 + (i * 0x800)); |
926 | } | 933 | } |
@@ -933,10 +940,11 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
933 | struct nouveau_object **pobject) | 940 | struct nouveau_object **pobject) |
934 | { | 941 | { |
935 | struct nv50_disp_priv *priv; | 942 | struct nv50_disp_priv *priv; |
943 | int heads = nv_rd32(parent, 0x022448); | ||
936 | int ret; | 944 | int ret; |
937 | 945 | ||
938 | ret = nouveau_disp_create(parent, engine, oclass, "PDISP", | 946 | ret = nouveau_disp_create(parent, engine, oclass, heads, |
939 | "display", &priv); | 947 | "PDISP", "display", &priv); |
940 | *pobject = nv_object(priv); | 948 | *pobject = nv_object(priv); |
941 | if (ret) | 949 | if (ret) |
942 | return ret; | 950 | return ret; |
@@ -944,8 +952,9 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
944 | nv_engine(priv)->sclass = nvd0_disp_base_oclass; | 952 | nv_engine(priv)->sclass = nvd0_disp_base_oclass; |
945 | nv_engine(priv)->cclass = &nv50_disp_cclass; | 953 | nv_engine(priv)->cclass = &nv50_disp_cclass; |
946 | nv_subdev(priv)->intr = nvd0_disp_intr; | 954 | nv_subdev(priv)->intr = nvd0_disp_intr; |
955 | INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor); | ||
947 | priv->sclass = nvd0_disp_sclass; | 956 | priv->sclass = nvd0_disp_sclass; |
948 | priv->head.nr = nv_rd32(priv, 0x022448); | 957 | priv->head.nr = heads; |
949 | priv->dac.nr = 3; | 958 | priv->dac.nr = 3; |
950 | priv->sor.nr = 4; | 959 | priv->sor.nr = 4; |
951 | priv->dac.power = nv50_dac_power; | 960 | priv->dac.power = nv50_dac_power; |
@@ -953,14 +962,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
953 | priv->sor.power = nv50_sor_power; | 962 | priv->sor.power = nv50_sor_power; |
954 | priv->sor.hda_eld = nvd0_hda_eld; | 963 | priv->sor.hda_eld = nvd0_hda_eld; |
955 | priv->sor.hdmi = nvd0_hdmi_ctrl; | 964 | priv->sor.hdmi = nvd0_hdmi_ctrl; |
956 | priv->sor.dp_train = nvd0_sor_dp_train; | 965 | priv->sor.dp = &nvd0_sor_dp_func; |
957 | priv->sor.dp_train_init = nv94_sor_dp_train_init; | ||
958 | priv->sor.dp_train_fini = nv94_sor_dp_train_fini; | ||
959 | priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl; | ||
960 | priv->sor.dp_drvctl = nvd0_sor_dp_drvctl; | ||
961 | |||
962 | INIT_LIST_HEAD(&priv->base.vblank.list); | ||
963 | spin_lock_init(&priv->base.vblank.lock); | ||
964 | return 0; | 966 | return 0; |
965 | } | 967 | } |
966 | 968 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c index 259537c4587e..20725b363d58 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c | |||
@@ -51,10 +51,11 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
51 | struct nouveau_object **pobject) | 51 | struct nouveau_object **pobject) |
52 | { | 52 | { |
53 | struct nv50_disp_priv *priv; | 53 | struct nv50_disp_priv *priv; |
54 | int heads = nv_rd32(parent, 0x022448); | ||
54 | int ret; | 55 | int ret; |
55 | 56 | ||
56 | ret = nouveau_disp_create(parent, engine, oclass, "PDISP", | 57 | ret = nouveau_disp_create(parent, engine, oclass, heads, |
57 | "display", &priv); | 58 | "PDISP", "display", &priv); |
58 | *pobject = nv_object(priv); | 59 | *pobject = nv_object(priv); |
59 | if (ret) | 60 | if (ret) |
60 | return ret; | 61 | return ret; |
@@ -62,8 +63,9 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
62 | nv_engine(priv)->sclass = nve0_disp_base_oclass; | 63 | nv_engine(priv)->sclass = nve0_disp_base_oclass; |
63 | nv_engine(priv)->cclass = &nv50_disp_cclass; | 64 | nv_engine(priv)->cclass = &nv50_disp_cclass; |
64 | nv_subdev(priv)->intr = nvd0_disp_intr; | 65 | nv_subdev(priv)->intr = nvd0_disp_intr; |
66 | INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor); | ||
65 | priv->sclass = nve0_disp_sclass; | 67 | priv->sclass = nve0_disp_sclass; |
66 | priv->head.nr = nv_rd32(priv, 0x022448); | 68 | priv->head.nr = heads; |
67 | priv->dac.nr = 3; | 69 | priv->dac.nr = 3; |
68 | priv->sor.nr = 4; | 70 | priv->sor.nr = 4; |
69 | priv->dac.power = nv50_dac_power; | 71 | priv->dac.power = nv50_dac_power; |
@@ -71,14 +73,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
71 | priv->sor.power = nv50_sor_power; | 73 | priv->sor.power = nv50_sor_power; |
72 | priv->sor.hda_eld = nvd0_hda_eld; | 74 | priv->sor.hda_eld = nvd0_hda_eld; |
73 | priv->sor.hdmi = nvd0_hdmi_ctrl; | 75 | priv->sor.hdmi = nvd0_hdmi_ctrl; |
74 | priv->sor.dp_train = nvd0_sor_dp_train; | 76 | priv->sor.dp = &nvd0_sor_dp_func; |
75 | priv->sor.dp_train_init = nv94_sor_dp_train_init; | ||
76 | priv->sor.dp_train_fini = nv94_sor_dp_train_fini; | ||
77 | priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl; | ||
78 | priv->sor.dp_drvctl = nvd0_sor_dp_drvctl; | ||
79 | |||
80 | INIT_LIST_HEAD(&priv->base.vblank.list); | ||
81 | spin_lock_init(&priv->base.vblank.lock); | ||
82 | return 0; | 77 | return 0; |
83 | } | 78 | } |
84 | 79 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c new file mode 100644 index 000000000000..2c8ce351b52d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Ben Skeggs | ||
23 | */ | ||
24 | |||
25 | #include <core/os.h> | ||
26 | #include <core/class.h> | ||
27 | |||
28 | #include <subdev/bios.h> | ||
29 | #include <subdev/bios/dcb.h> | ||
30 | #include <subdev/timer.h> | ||
31 | #include <subdev/i2c.h> | ||
32 | |||
33 | #include "nv50.h" | ||
34 | |||
35 | /****************************************************************************** | ||
36 | * DisplayPort | ||
37 | *****************************************************************************/ | ||
38 | static struct nouveau_i2c_port * | ||
39 | nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp) | ||
40 | { | ||
41 | struct nouveau_i2c *i2c = nouveau_i2c(disp); | ||
42 | return i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev)); | ||
43 | } | ||
44 | |||
45 | static int | ||
46 | nv50_pior_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, | ||
47 | int head, int pattern) | ||
48 | { | ||
49 | struct nouveau_i2c_port *port; | ||
50 | int ret = -EINVAL; | ||
51 | |||
52 | port = nv50_pior_dp_find(disp, outp); | ||
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 | } | ||
62 | |||
63 | static int | ||
64 | nv50_pior_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, | ||
65 | int head, int lane_nr, int link_bw, bool enh) | ||
66 | { | ||
67 | struct nouveau_i2c_port *port; | ||
68 | int ret = -EINVAL; | ||
69 | |||
70 | port = nv50_pior_dp_find(disp, outp); | ||
71 | if (port && port->func->lnk_ctl) | ||
72 | ret = port->func->lnk_ctl(port, lane_nr, link_bw, enh); | ||
73 | |||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | static int | ||
78 | nv50_pior_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, | ||
79 | int head, int lane, int vsw, int pre) | ||
80 | { | ||
81 | struct nouveau_i2c_port *port; | ||
82 | int ret = -EINVAL; | ||
83 | |||
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 | |||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | const struct nouveau_dp_func | ||
96 | nv50_pior_dp_func = { | ||
97 | .pattern = nv50_pior_dp_pattern, | ||
98 | .lnk_ctl = nv50_pior_dp_lnk_ctl, | ||
99 | .drv_ctl = nv50_pior_dp_drv_ctl, | ||
100 | }; | ||
101 | |||
102 | /****************************************************************************** | ||
103 | * General PIOR handling | ||
104 | *****************************************************************************/ | ||
105 | int | ||
106 | nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data) | ||
107 | { | ||
108 | const u32 stat = data & NV50_DISP_PIOR_PWR_STATE; | ||
109 | const u32 soff = (or * 0x800); | ||
110 | nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000); | ||
111 | nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | stat); | ||
112 | nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000); | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | int | ||
117 | nv50_pior_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) | ||
118 | { | ||
119 | struct nv50_disp_priv *priv = (void *)object->engine; | ||
120 | const u8 type = (mthd & NV50_DISP_PIOR_MTHD_TYPE) >> 12; | ||
121 | const u8 or = (mthd & NV50_DISP_PIOR_MTHD_OR); | ||
122 | u32 *data = args; | ||
123 | int ret; | ||
124 | |||
125 | if (size < sizeof(u32)) | ||
126 | return -EINVAL; | ||
127 | |||
128 | mthd &= ~NV50_DISP_PIOR_MTHD_TYPE; | ||
129 | mthd &= ~NV50_DISP_PIOR_MTHD_OR; | ||
130 | switch (mthd) { | ||
131 | case NV50_DISP_PIOR_PWR: | ||
132 | ret = priv->pior.power(priv, or, data[0]); | ||
133 | priv->pior.type[or] = type; | ||
134 | break; | ||
135 | default: | ||
136 | return -EINVAL; | ||
137 | } | ||
138 | |||
139 | return ret; | ||
140 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c index 39b6b67732d0..ab1e918469a8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c | |||
@@ -79,31 +79,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) | |||
79 | priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID; | 79 | priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID; |
80 | ret = 0; | 80 | ret = 0; |
81 | break; | 81 | break; |
82 | case NV94_DISP_SOR_DP_TRAIN: | ||
83 | switch (data & NV94_DISP_SOR_DP_TRAIN_OP) { | ||
84 | case NV94_DISP_SOR_DP_TRAIN_OP_PATTERN: | ||
85 | ret = priv->sor.dp_train(priv, or, link, type, mask, data, &outp); | ||
86 | break; | ||
87 | case NV94_DISP_SOR_DP_TRAIN_OP_INIT: | ||
88 | ret = priv->sor.dp_train_init(priv, or, link, head, type, mask, data, &outp); | ||
89 | break; | ||
90 | case NV94_DISP_SOR_DP_TRAIN_OP_FINI: | ||
91 | ret = priv->sor.dp_train_fini(priv, or, link, head, type, mask, data, &outp); | ||
92 | break; | ||
93 | default: | ||
94 | break; | ||
95 | } | ||
96 | break; | ||
97 | case NV94_DISP_SOR_DP_LNKCTL: | ||
98 | ret = priv->sor.dp_lnkctl(priv, or, link, head, type, mask, data, &outp); | ||
99 | break; | ||
100 | case NV94_DISP_SOR_DP_DRVCTL(0): | ||
101 | case NV94_DISP_SOR_DP_DRVCTL(1): | ||
102 | case NV94_DISP_SOR_DP_DRVCTL(2): | ||
103 | case NV94_DISP_SOR_DP_DRVCTL(3): | ||
104 | ret = priv->sor.dp_drvctl(priv, or, link, (mthd & 0xc0) >> 6, | ||
105 | type, mask, data, &outp); | ||
106 | break; | ||
107 | default: | 82 | default: |
108 | BUG_ON(1); | 83 | BUG_ON(1); |
109 | } | 84 | } |
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c index f6edd009762e..7ec4ee83fb64 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c | |||
@@ -33,124 +33,53 @@ | |||
33 | #include "nv50.h" | 33 | #include "nv50.h" |
34 | 34 | ||
35 | static inline u32 | 35 | static inline u32 |
36 | nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) | 36 | nv94_sor_soff(struct dcb_output *outp) |
37 | { | 37 | { |
38 | static const u8 nvaf[] = { 24, 16, 8, 0 }; /* thanks, apple.. */ | 38 | return (ffs(outp->or) - 1) * 0x800; |
39 | static const u8 nv94[] = { 16, 8, 0, 24 }; | ||
40 | if (nv_device(priv)->chipset == 0xaf) | ||
41 | return nvaf[lane]; | ||
42 | return nv94[lane]; | ||
43 | } | 39 | } |
44 | 40 | ||
45 | int | 41 | static inline u32 |
46 | nv94_sor_dp_train_init(struct nv50_disp_priv *priv, int or, int link, int head, | 42 | nv94_sor_loff(struct dcb_output *outp) |
47 | u16 type, u16 mask, u32 data, struct dcb_output *dcbo) | ||
48 | { | 43 | { |
49 | struct nouveau_bios *bios = nouveau_bios(priv); | 44 | return nv94_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80; |
50 | struct nvbios_dpout info; | ||
51 | u8 ver, hdr, cnt, len; | ||
52 | u16 outp; | ||
53 | |||
54 | outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info); | ||
55 | if (outp) { | ||
56 | struct nvbios_init init = { | ||
57 | .subdev = nv_subdev(priv), | ||
58 | .bios = bios, | ||
59 | .outp = dcbo, | ||
60 | .crtc = head, | ||
61 | .execute = 1, | ||
62 | }; | ||
63 | |||
64 | if (data & NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_ON) | ||
65 | init.offset = info.script[2]; | ||
66 | else | ||
67 | init.offset = info.script[3]; | ||
68 | nvbios_exec(&init); | ||
69 | |||
70 | init.offset = info.script[0]; | ||
71 | nvbios_exec(&init); | ||
72 | } | ||
73 | |||
74 | return 0; | ||
75 | } | 45 | } |
76 | 46 | ||
77 | int | 47 | static inline u32 |
78 | nv94_sor_dp_train_fini(struct nv50_disp_priv *priv, int or, int link, int head, | 48 | nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) |
79 | u16 type, u16 mask, u32 data, struct dcb_output *dcbo) | ||
80 | { | 49 | { |
81 | struct nouveau_bios *bios = nouveau_bios(priv); | 50 | static const u8 nvaf[] = { 24, 16, 8, 0 }; /* thanks, apple.. */ |
82 | struct nvbios_dpout info; | 51 | static const u8 nv94[] = { 16, 8, 0, 24 }; |
83 | u8 ver, hdr, cnt, len; | 52 | if (nv_device(priv)->chipset == 0xaf) |
84 | u16 outp; | 53 | return nvaf[lane]; |
85 | 54 | return nv94[lane]; | |
86 | outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info); | ||
87 | if (outp) { | ||
88 | struct nvbios_init init = { | ||
89 | .subdev = nv_subdev(priv), | ||
90 | .bios = bios, | ||
91 | .offset = info.script[1], | ||
92 | .outp = dcbo, | ||
93 | .crtc = head, | ||
94 | .execute = 1, | ||
95 | }; | ||
96 | |||
97 | nvbios_exec(&init); | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | 55 | } |
102 | 56 | ||
103 | int | 57 | static int |
104 | nv94_sor_dp_train(struct nv50_disp_priv *priv, int or, int link, | 58 | nv94_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, |
105 | u16 type, u16 mask, u32 data, struct dcb_output *info) | 59 | int head, int pattern) |
106 | { | 60 | { |
107 | const u32 loff = (or * 0x800) + (link * 0x80); | 61 | struct nv50_disp_priv *priv = (void *)disp; |
108 | const u32 patt = (data & NV94_DISP_SOR_DP_TRAIN_PATTERN); | 62 | const u32 loff = nv94_sor_loff(outp); |
109 | nv_mask(priv, 0x61c10c + loff, 0x0f000000, patt << 24); | 63 | nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24); |
110 | return 0; | 64 | return 0; |
111 | } | 65 | } |
112 | 66 | ||
113 | int | 67 | static int |
114 | nv94_sor_dp_lnkctl(struct nv50_disp_priv *priv, int or, int link, int head, | 68 | nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, |
115 | u16 type, u16 mask, u32 data, struct dcb_output *dcbo) | 69 | int head, int link_nr, int link_bw, bool enh_frame) |
116 | { | 70 | { |
117 | struct nouveau_bios *bios = nouveau_bios(priv); | 71 | struct nv50_disp_priv *priv = (void *)disp; |
118 | const u32 loff = (or * 0x800) + (link * 0x80); | 72 | const u32 soff = nv94_sor_soff(outp); |
119 | const u32 soff = (or * 0x800); | 73 | const u32 loff = nv94_sor_loff(outp); |
120 | u16 link_bw = (data & NV94_DISP_SOR_DP_LNKCTL_WIDTH) >> 8; | ||
121 | u8 link_nr = (data & NV94_DISP_SOR_DP_LNKCTL_COUNT); | ||
122 | u32 dpctrl = 0x00000000; | 74 | u32 dpctrl = 0x00000000; |
123 | u32 clksor = 0x00000000; | 75 | u32 clksor = 0x00000000; |
124 | u32 outp, lane = 0; | 76 | u32 lane = 0; |
125 | u8 ver, hdr, cnt, len; | ||
126 | struct nvbios_dpout info; | ||
127 | int i; | 77 | int i; |
128 | 78 | ||
129 | /* -> 10Khz units */ | ||
130 | link_bw *= 2700; | ||
131 | |||
132 | outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info); | ||
133 | if (outp && info.lnkcmp) { | ||
134 | struct nvbios_init init = { | ||
135 | .subdev = nv_subdev(priv), | ||
136 | .bios = bios, | ||
137 | .offset = 0x0000, | ||
138 | .outp = dcbo, | ||
139 | .crtc = head, | ||
140 | .execute = 1, | ||
141 | }; | ||
142 | |||
143 | while (link_bw < nv_ro16(bios, info.lnkcmp)) | ||
144 | info.lnkcmp += 4; | ||
145 | init.offset = nv_ro16(bios, info.lnkcmp + 2); | ||
146 | |||
147 | nvbios_exec(&init); | ||
148 | } | ||
149 | |||
150 | dpctrl |= ((1 << link_nr) - 1) << 16; | 79 | dpctrl |= ((1 << link_nr) - 1) << 16; |
151 | if (data & NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH) | 80 | if (enh_frame) |
152 | dpctrl |= 0x00004000; | 81 | dpctrl |= 0x00004000; |
153 | if (link_bw > 16200) | 82 | if (link_bw > 0x06) |
154 | clksor |= 0x00040000; | 83 | clksor |= 0x00040000; |
155 | 84 | ||
156 | for (i = 0; i < link_nr; i++) | 85 | for (i = 0; i < link_nr; i++) |
@@ -162,24 +91,25 @@ nv94_sor_dp_lnkctl(struct nv50_disp_priv *priv, int or, int link, int head, | |||
162 | return 0; | 91 | return 0; |
163 | } | 92 | } |
164 | 93 | ||
165 | int | 94 | static int |
166 | nv94_sor_dp_drvctl(struct nv50_disp_priv *priv, int or, int link, int lane, | 95 | nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, |
167 | u16 type, u16 mask, u32 data, struct dcb_output *dcbo) | 96 | int head, int lane, int swing, int preem) |
168 | { | 97 | { |
169 | struct nouveau_bios *bios = nouveau_bios(priv); | 98 | struct nouveau_bios *bios = nouveau_bios(disp); |
170 | const u32 loff = (or * 0x800) + (link * 0x80); | 99 | struct nv50_disp_priv *priv = (void *)disp; |
171 | const u8 swing = (data & NV94_DISP_SOR_DP_DRVCTL_VS) >> 8; | 100 | const u32 loff = nv94_sor_loff(outp); |
172 | const u8 preem = (data & NV94_DISP_SOR_DP_DRVCTL_PE); | ||
173 | u32 addr, shift = nv94_sor_dp_lane_map(priv, lane); | 101 | u32 addr, shift = nv94_sor_dp_lane_map(priv, lane); |
174 | u8 ver, hdr, cnt, len; | 102 | u8 ver, hdr, cnt, len; |
175 | struct nvbios_dpout outp; | 103 | struct nvbios_dpout info; |
176 | struct nvbios_dpcfg ocfg; | 104 | struct nvbios_dpcfg ocfg; |
177 | 105 | ||
178 | addr = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &outp); | 106 | addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm, |
107 | &ver, &hdr, &cnt, &len, &info); | ||
179 | if (!addr) | 108 | if (!addr) |
180 | return -ENODEV; | 109 | return -ENODEV; |
181 | 110 | ||
182 | addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, &ver, &hdr, &cnt, &len, &ocfg); | 111 | addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, |
112 | &ver, &hdr, &cnt, &len, &ocfg); | ||
183 | if (!addr) | 113 | if (!addr) |
184 | return -EINVAL; | 114 | return -EINVAL; |
185 | 115 | ||
@@ -188,3 +118,10 @@ nv94_sor_dp_drvctl(struct nv50_disp_priv *priv, int or, int link, int lane, | |||
188 | nv_mask(priv, 0x61c130 + loff, 0x0000ff00, ocfg.unk << 8); | 118 | nv_mask(priv, 0x61c130 + loff, 0x0000ff00, ocfg.unk << 8); |
189 | return 0; | 119 | return 0; |
190 | } | 120 | } |
121 | |||
122 | const struct nouveau_dp_func | ||
123 | nv94_sor_dp_func = { | ||
124 | .pattern = nv94_sor_dp_pattern, | ||
125 | .lnk_ctl = nv94_sor_dp_lnk_ctl, | ||
126 | .drv_ctl = nv94_sor_dp_drv_ctl, | ||
127 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c index c37ce7e29f5d..9e1d435d7282 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c | |||
@@ -33,59 +33,49 @@ | |||
33 | #include "nv50.h" | 33 | #include "nv50.h" |
34 | 34 | ||
35 | static inline u32 | 35 | static inline u32 |
36 | nvd0_sor_soff(struct dcb_output *outp) | ||
37 | { | ||
38 | return (ffs(outp->or) - 1) * 0x800; | ||
39 | } | ||
40 | |||
41 | static inline u32 | ||
42 | nvd0_sor_loff(struct dcb_output *outp) | ||
43 | { | ||
44 | return nvd0_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80; | ||
45 | } | ||
46 | |||
47 | static inline u32 | ||
36 | nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) | 48 | nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) |
37 | { | 49 | { |
38 | static const u8 nvd0[] = { 16, 8, 0, 24 }; | 50 | static const u8 nvd0[] = { 16, 8, 0, 24 }; |
39 | return nvd0[lane]; | 51 | return nvd0[lane]; |
40 | } | 52 | } |
41 | 53 | ||
42 | int | 54 | static int |
43 | nvd0_sor_dp_train(struct nv50_disp_priv *priv, int or, int link, | 55 | nvd0_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, |
44 | u16 type, u16 mask, u32 data, struct dcb_output *info) | 56 | int head, int pattern) |
45 | { | 57 | { |
46 | const u32 loff = (or * 0x800) + (link * 0x80); | 58 | struct nv50_disp_priv *priv = (void *)disp; |
47 | const u32 patt = (data & NV94_DISP_SOR_DP_TRAIN_PATTERN); | 59 | const u32 loff = nvd0_sor_loff(outp); |
48 | nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * patt); | 60 | nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); |
49 | return 0; | 61 | return 0; |
50 | } | 62 | } |
51 | 63 | ||
52 | int | 64 | static int |
53 | nvd0_sor_dp_lnkctl(struct nv50_disp_priv *priv, int or, int link, int head, | 65 | nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, |
54 | u16 type, u16 mask, u32 data, struct dcb_output *dcbo) | 66 | int head, int link_nr, int link_bw, bool enh_frame) |
55 | { | 67 | { |
56 | struct nouveau_bios *bios = nouveau_bios(priv); | 68 | struct nv50_disp_priv *priv = (void *)disp; |
57 | const u32 loff = (or * 0x800) + (link * 0x80); | 69 | const u32 soff = nvd0_sor_soff(outp); |
58 | const u32 soff = (or * 0x800); | 70 | const u32 loff = nvd0_sor_loff(outp); |
59 | const u8 link_bw = (data & NV94_DISP_SOR_DP_LNKCTL_WIDTH) >> 8; | ||
60 | const u8 link_nr = (data & NV94_DISP_SOR_DP_LNKCTL_COUNT); | ||
61 | u32 dpctrl = 0x00000000; | 71 | u32 dpctrl = 0x00000000; |
62 | u32 clksor = 0x00000000; | 72 | u32 clksor = 0x00000000; |
63 | u32 outp, lane = 0; | 73 | u32 lane = 0; |
64 | u8 ver, hdr, cnt, len; | ||
65 | struct nvbios_dpout info; | ||
66 | int i; | 74 | int i; |
67 | 75 | ||
68 | outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info); | ||
69 | if (outp && info.lnkcmp) { | ||
70 | struct nvbios_init init = { | ||
71 | .subdev = nv_subdev(priv), | ||
72 | .bios = bios, | ||
73 | .offset = 0x0000, | ||
74 | .outp = dcbo, | ||
75 | .crtc = head, | ||
76 | .execute = 1, | ||
77 | }; | ||
78 | |||
79 | while (nv_ro08(bios, info.lnkcmp) < link_bw) | ||
80 | info.lnkcmp += 3; | ||
81 | init.offset = nv_ro16(bios, info.lnkcmp + 1); | ||
82 | |||
83 | nvbios_exec(&init); | ||
84 | } | ||
85 | |||
86 | clksor |= link_bw << 18; | 76 | clksor |= link_bw << 18; |
87 | dpctrl |= ((1 << link_nr) - 1) << 16; | 77 | dpctrl |= ((1 << link_nr) - 1) << 16; |
88 | if (data & NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH) | 78 | if (enh_frame) |
89 | dpctrl |= 0x00004000; | 79 | dpctrl |= 0x00004000; |
90 | 80 | ||
91 | for (i = 0; i < link_nr; i++) | 81 | for (i = 0; i < link_nr; i++) |
@@ -97,24 +87,25 @@ nvd0_sor_dp_lnkctl(struct nv50_disp_priv *priv, int or, int link, int head, | |||
97 | return 0; | 87 | return 0; |
98 | } | 88 | } |
99 | 89 | ||
100 | int | 90 | static int |
101 | nvd0_sor_dp_drvctl(struct nv50_disp_priv *priv, int or, int link, int lane, | 91 | nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, |
102 | u16 type, u16 mask, u32 data, struct dcb_output *dcbo) | 92 | int head, int lane, int swing, int preem) |
103 | { | 93 | { |
104 | struct nouveau_bios *bios = nouveau_bios(priv); | 94 | struct nouveau_bios *bios = nouveau_bios(disp); |
105 | const u32 loff = (or * 0x800) + (link * 0x80); | 95 | struct nv50_disp_priv *priv = (void *)disp; |
106 | const u8 swing = (data & NV94_DISP_SOR_DP_DRVCTL_VS) >> 8; | 96 | const u32 loff = nvd0_sor_loff(outp); |
107 | const u8 preem = (data & NV94_DISP_SOR_DP_DRVCTL_PE); | ||
108 | u32 addr, shift = nvd0_sor_dp_lane_map(priv, lane); | 97 | u32 addr, shift = nvd0_sor_dp_lane_map(priv, lane); |
109 | u8 ver, hdr, cnt, len; | 98 | u8 ver, hdr, cnt, len; |
110 | struct nvbios_dpout outp; | 99 | struct nvbios_dpout info; |
111 | struct nvbios_dpcfg ocfg; | 100 | struct nvbios_dpcfg ocfg; |
112 | 101 | ||
113 | addr = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &outp); | 102 | addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm, |
103 | &ver, &hdr, &cnt, &len, &info); | ||
114 | if (!addr) | 104 | if (!addr) |
115 | return -ENODEV; | 105 | return -ENODEV; |
116 | 106 | ||
117 | addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, &ver, &hdr, &cnt, &len, &ocfg); | 107 | addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, |
108 | &ver, &hdr, &cnt, &len, &ocfg); | ||
118 | if (!addr) | 109 | if (!addr) |
119 | return -EINVAL; | 110 | return -EINVAL; |
120 | 111 | ||
@@ -124,3 +115,10 @@ nvd0_sor_dp_drvctl(struct nv50_disp_priv *priv, int or, int link, int lane, | |||
124 | nv_mask(priv, 0x61c13c + loff, 0x00000000, 0x00000000); | 115 | nv_mask(priv, 0x61c13c + loff, 0x00000000, 0x00000000); |
125 | return 0; | 116 | return 0; |
126 | } | 117 | } |
118 | |||
119 | const struct nouveau_dp_func | ||
120 | nvd0_sor_dp_func = { | ||
121 | .pattern = nvd0_sor_dp_pattern, | ||
122 | .lnk_ctl = nvd0_sor_dp_lnk_ctl, | ||
123 | .drv_ctl = nvd0_sor_dp_drv_ctl, | ||
124 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c index c2b9db335816..7341ebe131fa 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c | |||
@@ -22,8 +22,10 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/client.h> | ||
25 | #include <core/object.h> | 26 | #include <core/object.h> |
26 | #include <core/handle.h> | 27 | #include <core/handle.h> |
28 | #include <core/event.h> | ||
27 | #include <core/class.h> | 29 | #include <core/class.h> |
28 | 30 | ||
29 | #include <engine/dmaobj.h> | 31 | #include <engine/dmaobj.h> |
@@ -146,10 +148,25 @@ nouveau_fifo_chid(struct nouveau_fifo *priv, struct nouveau_object *object) | |||
146 | return -1; | 148 | return -1; |
147 | } | 149 | } |
148 | 150 | ||
151 | const char * | ||
152 | nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid) | ||
153 | { | ||
154 | struct nouveau_fifo_chan *chan = NULL; | ||
155 | unsigned long flags; | ||
156 | |||
157 | spin_lock_irqsave(&fifo->lock, flags); | ||
158 | if (chid >= fifo->min && chid <= fifo->max) | ||
159 | chan = (void *)fifo->channel[chid]; | ||
160 | spin_unlock_irqrestore(&fifo->lock, flags); | ||
161 | |||
162 | return nouveau_client_name(chan); | ||
163 | } | ||
164 | |||
149 | void | 165 | void |
150 | nouveau_fifo_destroy(struct nouveau_fifo *priv) | 166 | nouveau_fifo_destroy(struct nouveau_fifo *priv) |
151 | { | 167 | { |
152 | kfree(priv->channel); | 168 | kfree(priv->channel); |
169 | nouveau_event_destroy(&priv->uevent); | ||
153 | nouveau_engine_destroy(&priv->base); | 170 | nouveau_engine_destroy(&priv->base); |
154 | } | 171 | } |
155 | 172 | ||
@@ -174,6 +191,10 @@ nouveau_fifo_create_(struct nouveau_object *parent, | |||
174 | if (!priv->channel) | 191 | if (!priv->channel) |
175 | return -ENOMEM; | 192 | return -ENOMEM; |
176 | 193 | ||
194 | ret = nouveau_event_create(1, &priv->uevent); | ||
195 | if (ret) | ||
196 | return ret; | ||
197 | |||
177 | priv->chid = nouveau_fifo_chid; | 198 | priv->chid = nouveau_fifo_chid; |
178 | spin_lock_init(&priv->lock); | 199 | spin_lock_init(&priv->lock); |
179 | return 0; | 200 | return 0; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c index a47a8548f9e0..f877bd524a92 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <core/namedb.h> | 28 | #include <core/namedb.h> |
29 | #include <core/handle.h> | 29 | #include <core/handle.h> |
30 | #include <core/ramht.h> | 30 | #include <core/ramht.h> |
31 | #include <core/event.h> | ||
31 | 32 | ||
32 | #include <subdev/instmem.h> | 33 | #include <subdev/instmem.h> |
33 | #include <subdev/instmem/nv04.h> | 34 | #include <subdev/instmem/nv04.h> |
@@ -398,6 +399,98 @@ out: | |||
398 | return handled; | 399 | return handled; |
399 | } | 400 | } |
400 | 401 | ||
402 | static void | ||
403 | nv04_fifo_cache_error(struct nouveau_device *device, | ||
404 | struct nv04_fifo_priv *priv, u32 chid, u32 get) | ||
405 | { | ||
406 | u32 mthd, data; | ||
407 | int ptr; | ||
408 | |||
409 | /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before wrapping on my | ||
410 | * G80 chips, but CACHE1 isn't big enough for this much data.. Tests | ||
411 | * show that it wraps around to the start at GET=0x800.. No clue as to | ||
412 | * why.. | ||
413 | */ | ||
414 | ptr = (get & 0x7ff) >> 2; | ||
415 | |||
416 | if (device->card_type < NV_40) { | ||
417 | mthd = nv_rd32(priv, NV04_PFIFO_CACHE1_METHOD(ptr)); | ||
418 | data = nv_rd32(priv, NV04_PFIFO_CACHE1_DATA(ptr)); | ||
419 | } else { | ||
420 | mthd = nv_rd32(priv, NV40_PFIFO_CACHE1_METHOD(ptr)); | ||
421 | data = nv_rd32(priv, NV40_PFIFO_CACHE1_DATA(ptr)); | ||
422 | } | ||
423 | |||
424 | if (!nv04_fifo_swmthd(priv, chid, mthd, data)) { | ||
425 | const char *client_name = | ||
426 | nouveau_client_name_for_fifo_chid(&priv->base, chid); | ||
427 | nv_error(priv, | ||
428 | "CACHE_ERROR - ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", | ||
429 | chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc, | ||
430 | data); | ||
431 | } | ||
432 | |||
433 | nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0); | ||
434 | nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); | ||
435 | |||
436 | nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, | ||
437 | nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1); | ||
438 | nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); | ||
439 | nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, | ||
440 | nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1); | ||
441 | nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0); | ||
442 | |||
443 | nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, | ||
444 | nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); | ||
445 | nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); | ||
446 | } | ||
447 | |||
448 | static void | ||
449 | nv04_fifo_dma_pusher(struct nouveau_device *device, struct nv04_fifo_priv *priv, | ||
450 | u32 chid) | ||
451 | { | ||
452 | const char *client_name; | ||
453 | u32 dma_get = nv_rd32(priv, 0x003244); | ||
454 | u32 dma_put = nv_rd32(priv, 0x003240); | ||
455 | u32 push = nv_rd32(priv, 0x003220); | ||
456 | u32 state = nv_rd32(priv, 0x003228); | ||
457 | |||
458 | client_name = nouveau_client_name_for_fifo_chid(&priv->base, chid); | ||
459 | |||
460 | if (device->card_type == NV_50) { | ||
461 | u32 ho_get = nv_rd32(priv, 0x003328); | ||
462 | u32 ho_put = nv_rd32(priv, 0x003320); | ||
463 | u32 ib_get = nv_rd32(priv, 0x003334); | ||
464 | u32 ib_put = nv_rd32(priv, 0x003330); | ||
465 | |||
466 | nv_error(priv, | ||
467 | "DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n", | ||
468 | chid, client_name, ho_get, dma_get, ho_put, dma_put, | ||
469 | ib_get, ib_put, state, nv_dma_state_err(state), push); | ||
470 | |||
471 | /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ | ||
472 | nv_wr32(priv, 0x003364, 0x00000000); | ||
473 | if (dma_get != dma_put || ho_get != ho_put) { | ||
474 | nv_wr32(priv, 0x003244, dma_put); | ||
475 | nv_wr32(priv, 0x003328, ho_put); | ||
476 | } else | ||
477 | if (ib_get != ib_put) | ||
478 | nv_wr32(priv, 0x003334, ib_put); | ||
479 | } else { | ||
480 | nv_error(priv, | ||
481 | "DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n", | ||
482 | chid, client_name, dma_get, dma_put, state, | ||
483 | nv_dma_state_err(state), push); | ||
484 | |||
485 | if (dma_get != dma_put) | ||
486 | nv_wr32(priv, 0x003244, dma_put); | ||
487 | } | ||
488 | |||
489 | nv_wr32(priv, 0x003228, 0x00000000); | ||
490 | nv_wr32(priv, 0x003220, 0x00000001); | ||
491 | nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); | ||
492 | } | ||
493 | |||
401 | void | 494 | void |
402 | nv04_fifo_intr(struct nouveau_subdev *subdev) | 495 | nv04_fifo_intr(struct nouveau_subdev *subdev) |
403 | { | 496 | { |
@@ -416,96 +509,12 @@ nv04_fifo_intr(struct nouveau_subdev *subdev) | |||
416 | get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET); | 509 | get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET); |
417 | 510 | ||
418 | if (status & NV_PFIFO_INTR_CACHE_ERROR) { | 511 | if (status & NV_PFIFO_INTR_CACHE_ERROR) { |
419 | uint32_t mthd, data; | 512 | nv04_fifo_cache_error(device, priv, chid, get); |
420 | int ptr; | ||
421 | |||
422 | /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before | ||
423 | * wrapping on my G80 chips, but CACHE1 isn't big | ||
424 | * enough for this much data.. Tests show that it | ||
425 | * wraps around to the start at GET=0x800.. No clue | ||
426 | * as to why.. | ||
427 | */ | ||
428 | ptr = (get & 0x7ff) >> 2; | ||
429 | |||
430 | if (device->card_type < NV_40) { | ||
431 | mthd = nv_rd32(priv, | ||
432 | NV04_PFIFO_CACHE1_METHOD(ptr)); | ||
433 | data = nv_rd32(priv, | ||
434 | NV04_PFIFO_CACHE1_DATA(ptr)); | ||
435 | } else { | ||
436 | mthd = nv_rd32(priv, | ||
437 | NV40_PFIFO_CACHE1_METHOD(ptr)); | ||
438 | data = nv_rd32(priv, | ||
439 | NV40_PFIFO_CACHE1_DATA(ptr)); | ||
440 | } | ||
441 | |||
442 | if (!nv04_fifo_swmthd(priv, chid, mthd, data)) { | ||
443 | nv_error(priv, "CACHE_ERROR - Ch %d/%d " | ||
444 | "Mthd 0x%04x Data 0x%08x\n", | ||
445 | chid, (mthd >> 13) & 7, mthd & 0x1ffc, | ||
446 | data); | ||
447 | } | ||
448 | |||
449 | nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0); | ||
450 | nv_wr32(priv, NV03_PFIFO_INTR_0, | ||
451 | NV_PFIFO_INTR_CACHE_ERROR); | ||
452 | |||
453 | nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, | ||
454 | nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1); | ||
455 | nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); | ||
456 | nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, | ||
457 | nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1); | ||
458 | nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0); | ||
459 | |||
460 | nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, | ||
461 | nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); | ||
462 | nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); | ||
463 | |||
464 | status &= ~NV_PFIFO_INTR_CACHE_ERROR; | 513 | status &= ~NV_PFIFO_INTR_CACHE_ERROR; |
465 | } | 514 | } |
466 | 515 | ||
467 | if (status & NV_PFIFO_INTR_DMA_PUSHER) { | 516 | if (status & NV_PFIFO_INTR_DMA_PUSHER) { |
468 | u32 dma_get = nv_rd32(priv, 0x003244); | 517 | nv04_fifo_dma_pusher(device, priv, chid); |
469 | u32 dma_put = nv_rd32(priv, 0x003240); | ||
470 | u32 push = nv_rd32(priv, 0x003220); | ||
471 | u32 state = nv_rd32(priv, 0x003228); | ||
472 | |||
473 | if (device->card_type == NV_50) { | ||
474 | u32 ho_get = nv_rd32(priv, 0x003328); | ||
475 | u32 ho_put = nv_rd32(priv, 0x003320); | ||
476 | u32 ib_get = nv_rd32(priv, 0x003334); | ||
477 | u32 ib_put = nv_rd32(priv, 0x003330); | ||
478 | |||
479 | nv_error(priv, "DMA_PUSHER - Ch %d Get 0x%02x%08x " | ||
480 | "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " | ||
481 | "State 0x%08x (err: %s) Push 0x%08x\n", | ||
482 | chid, ho_get, dma_get, ho_put, | ||
483 | dma_put, ib_get, ib_put, state, | ||
484 | nv_dma_state_err(state), | ||
485 | push); | ||
486 | |||
487 | /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ | ||
488 | nv_wr32(priv, 0x003364, 0x00000000); | ||
489 | if (dma_get != dma_put || ho_get != ho_put) { | ||
490 | nv_wr32(priv, 0x003244, dma_put); | ||
491 | nv_wr32(priv, 0x003328, ho_put); | ||
492 | } else | ||
493 | if (ib_get != ib_put) { | ||
494 | nv_wr32(priv, 0x003334, ib_put); | ||
495 | } | ||
496 | } else { | ||
497 | nv_error(priv, "DMA_PUSHER - Ch %d Get 0x%08x " | ||
498 | "Put 0x%08x State 0x%08x (err: %s) Push 0x%08x\n", | ||
499 | chid, dma_get, dma_put, state, | ||
500 | nv_dma_state_err(state), push); | ||
501 | |||
502 | if (dma_get != dma_put) | ||
503 | nv_wr32(priv, 0x003244, dma_put); | ||
504 | } | ||
505 | |||
506 | nv_wr32(priv, 0x003228, 0x00000000); | ||
507 | nv_wr32(priv, 0x003220, 0x00000001); | ||
508 | nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); | ||
509 | status &= ~NV_PFIFO_INTR_DMA_PUSHER; | 518 | status &= ~NV_PFIFO_INTR_DMA_PUSHER; |
510 | } | 519 | } |
511 | 520 | ||
@@ -528,6 +537,12 @@ nv04_fifo_intr(struct nouveau_subdev *subdev) | |||
528 | status &= ~0x00000010; | 537 | status &= ~0x00000010; |
529 | nv_wr32(priv, 0x002100, 0x00000010); | 538 | nv_wr32(priv, 0x002100, 0x00000010); |
530 | } | 539 | } |
540 | |||
541 | if (status & 0x40000000) { | ||
542 | nouveau_event_trigger(priv->base.uevent, 0); | ||
543 | nv_wr32(priv, 0x002100, 0x40000000); | ||
544 | status &= ~0x40000000; | ||
545 | } | ||
531 | } | 546 | } |
532 | 547 | ||
533 | if (status) { | 548 | if (status) { |
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c index bd096364f680..840af6172788 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c | |||
@@ -129,7 +129,8 @@ nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend, | |||
129 | /* do the kickoff... */ | 129 | /* do the kickoff... */ |
130 | nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); | 130 | nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); |
131 | if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) { | 131 | if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) { |
132 | nv_error(priv, "channel %d unload timeout\n", chan->base.chid); | 132 | nv_error(priv, "channel %d [%s] unload timeout\n", |
133 | chan->base.chid, nouveau_client_name(chan)); | ||
133 | if (suspend) | 134 | if (suspend) |
134 | ret = -EBUSY; | 135 | ret = -EBUSY; |
135 | } | 136 | } |
@@ -480,7 +481,7 @@ nv50_fifo_init(struct nouveau_object *object) | |||
480 | nv_wr32(priv, 0x002044, 0x01003fff); | 481 | nv_wr32(priv, 0x002044, 0x01003fff); |
481 | 482 | ||
482 | nv_wr32(priv, 0x002100, 0xffffffff); | 483 | nv_wr32(priv, 0x002100, 0xffffffff); |
483 | nv_wr32(priv, 0x002140, 0xffffffff); | 484 | nv_wr32(priv, 0x002140, 0xbfffffff); |
484 | 485 | ||
485 | for (i = 0; i < 128; i++) | 486 | for (i = 0; i < 128; i++) |
486 | nv_wr32(priv, 0x002600 + (i * 4), 0x00000000); | 487 | nv_wr32(priv, 0x002600 + (i * 4), 0x00000000); |
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c index 1eb1c512f503..094000e87871 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <core/client.h> | 26 | #include <core/client.h> |
27 | #include <core/engctx.h> | 27 | #include <core/engctx.h> |
28 | #include <core/ramht.h> | 28 | #include <core/ramht.h> |
29 | #include <core/event.h> | ||
29 | #include <core/class.h> | 30 | #include <core/class.h> |
30 | #include <core/math.h> | 31 | #include <core/math.h> |
31 | 32 | ||
@@ -100,7 +101,8 @@ nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend, | |||
100 | done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff); | 101 | done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff); |
101 | nv_wr32(priv, 0x002520, save); | 102 | nv_wr32(priv, 0x002520, save); |
102 | if (!done) { | 103 | if (!done) { |
103 | nv_error(priv, "channel %d unload timeout\n", chan->base.chid); | 104 | nv_error(priv, "channel %d [%s] unload timeout\n", |
105 | chan->base.chid, nouveau_client_name(chan)); | ||
104 | if (suspend) | 106 | if (suspend) |
105 | return -EBUSY; | 107 | return -EBUSY; |
106 | } | 108 | } |
@@ -378,6 +380,20 @@ nv84_fifo_cclass = { | |||
378 | * PFIFO engine | 380 | * PFIFO engine |
379 | ******************************************************************************/ | 381 | ******************************************************************************/ |
380 | 382 | ||
383 | static void | ||
384 | nv84_fifo_uevent_enable(struct nouveau_event *event, int index) | ||
385 | { | ||
386 | struct nv84_fifo_priv *priv = event->priv; | ||
387 | nv_mask(priv, 0x002140, 0x40000000, 0x40000000); | ||
388 | } | ||
389 | |||
390 | static void | ||
391 | nv84_fifo_uevent_disable(struct nouveau_event *event, int index) | ||
392 | { | ||
393 | struct nv84_fifo_priv *priv = event->priv; | ||
394 | nv_mask(priv, 0x002140, 0x40000000, 0x00000000); | ||
395 | } | ||
396 | |||
381 | static int | 397 | static int |
382 | nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 398 | nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
383 | struct nouveau_oclass *oclass, void *data, u32 size, | 399 | struct nouveau_oclass *oclass, void *data, u32 size, |
@@ -401,6 +417,10 @@ nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
401 | if (ret) | 417 | if (ret) |
402 | return ret; | 418 | return ret; |
403 | 419 | ||
420 | priv->base.uevent->enable = nv84_fifo_uevent_enable; | ||
421 | priv->base.uevent->disable = nv84_fifo_uevent_disable; | ||
422 | priv->base.uevent->priv = priv; | ||
423 | |||
404 | nv_subdev(priv)->unit = 0x00000100; | 424 | nv_subdev(priv)->unit = 0x00000100; |
405 | nv_subdev(priv)->intr = nv04_fifo_intr; | 425 | nv_subdev(priv)->intr = nv04_fifo_intr; |
406 | nv_engine(priv)->cclass = &nv84_fifo_cclass; | 426 | nv_engine(priv)->cclass = &nv84_fifo_cclass; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index b4365dde1859..4f226afb5591 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <core/namedb.h> | 27 | #include <core/namedb.h> |
28 | #include <core/gpuobj.h> | 28 | #include <core/gpuobj.h> |
29 | #include <core/engctx.h> | 29 | #include <core/engctx.h> |
30 | #include <core/event.h> | ||
30 | #include <core/class.h> | 31 | #include <core/class.h> |
31 | #include <core/math.h> | 32 | #include <core/math.h> |
32 | #include <core/enum.h> | 33 | #include <core/enum.h> |
@@ -149,7 +150,8 @@ nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend, | |||
149 | 150 | ||
150 | nv_wr32(priv, 0x002634, chan->base.chid); | 151 | nv_wr32(priv, 0x002634, chan->base.chid); |
151 | if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { | 152 | if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { |
152 | nv_error(priv, "channel %d kick timeout\n", chan->base.chid); | 153 | nv_error(priv, "channel %d [%s] kick timeout\n", |
154 | chan->base.chid, nouveau_client_name(chan)); | ||
153 | if (suspend) | 155 | if (suspend) |
154 | return -EBUSY; | 156 | return -EBUSY; |
155 | } | 157 | } |
@@ -333,17 +335,17 @@ nvc0_fifo_cclass = { | |||
333 | ******************************************************************************/ | 335 | ******************************************************************************/ |
334 | 336 | ||
335 | static const struct nouveau_enum nvc0_fifo_fault_unit[] = { | 337 | static const struct nouveau_enum nvc0_fifo_fault_unit[] = { |
336 | { 0x00, "PGRAPH" }, | 338 | { 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR }, |
337 | { 0x03, "PEEPHOLE" }, | 339 | { 0x03, "PEEPHOLE" }, |
338 | { 0x04, "BAR1" }, | 340 | { 0x04, "BAR1" }, |
339 | { 0x05, "BAR3" }, | 341 | { 0x05, "BAR3" }, |
340 | { 0x07, "PFIFO" }, | 342 | { 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO }, |
341 | { 0x10, "PBSP" }, | 343 | { 0x10, "PBSP", NULL, NVDEV_ENGINE_BSP }, |
342 | { 0x11, "PPPP" }, | 344 | { 0x11, "PPPP", NULL, NVDEV_ENGINE_PPP }, |
343 | { 0x13, "PCOUNTER" }, | 345 | { 0x13, "PCOUNTER" }, |
344 | { 0x14, "PVP" }, | 346 | { 0x14, "PVP", NULL, NVDEV_ENGINE_VP }, |
345 | { 0x15, "PCOPY0" }, | 347 | { 0x15, "PCOPY0", NULL, NVDEV_ENGINE_COPY0 }, |
346 | { 0x16, "PCOPY1" }, | 348 | { 0x16, "PCOPY1", NULL, NVDEV_ENGINE_COPY1 }, |
347 | { 0x17, "PDAEMON" }, | 349 | { 0x17, "PDAEMON" }, |
348 | {} | 350 | {} |
349 | }; | 351 | }; |
@@ -402,6 +404,9 @@ nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit) | |||
402 | u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); | 404 | u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); |
403 | u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); | 405 | u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); |
404 | u32 client = (stat & 0x00001f00) >> 8; | 406 | u32 client = (stat & 0x00001f00) >> 8; |
407 | const struct nouveau_enum *en; | ||
408 | struct nouveau_engine *engine; | ||
409 | struct nouveau_object *engctx = NULL; | ||
405 | 410 | ||
406 | switch (unit) { | 411 | switch (unit) { |
407 | case 3: /* PEEPHOLE */ | 412 | case 3: /* PEEPHOLE */ |
@@ -420,16 +425,26 @@ nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit) | |||
420 | nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ? | 425 | nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ? |
421 | "write" : "read", (u64)vahi << 32 | valo); | 426 | "write" : "read", (u64)vahi << 32 | valo); |
422 | nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f); | 427 | nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f); |
423 | printk("] from "); | 428 | pr_cont("] from "); |
424 | nouveau_enum_print(nvc0_fifo_fault_unit, unit); | 429 | en = nouveau_enum_print(nvc0_fifo_fault_unit, unit); |
425 | if (stat & 0x00000040) { | 430 | if (stat & 0x00000040) { |
426 | printk("/"); | 431 | pr_cont("/"); |
427 | nouveau_enum_print(nvc0_fifo_fault_hubclient, client); | 432 | nouveau_enum_print(nvc0_fifo_fault_hubclient, client); |
428 | } else { | 433 | } else { |
429 | printk("/GPC%d/", (stat & 0x1f000000) >> 24); | 434 | pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24); |
430 | nouveau_enum_print(nvc0_fifo_fault_gpcclient, client); | 435 | nouveau_enum_print(nvc0_fifo_fault_gpcclient, client); |
431 | } | 436 | } |
432 | printk(" on channel 0x%010llx\n", (u64)inst << 12); | 437 | |
438 | if (en && en->data2) { | ||
439 | engine = nouveau_engine(priv, en->data2); | ||
440 | if (engine) | ||
441 | engctx = nouveau_engctx_get(engine, inst); | ||
442 | |||
443 | } | ||
444 | pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12, | ||
445 | nouveau_client_name(engctx)); | ||
446 | |||
447 | nouveau_engctx_put(engctx); | ||
433 | } | 448 | } |
434 | 449 | ||
435 | static int | 450 | static int |
@@ -484,10 +499,12 @@ nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit) | |||
484 | if (show) { | 499 | if (show) { |
485 | nv_error(priv, "SUBFIFO%d:", unit); | 500 | nv_error(priv, "SUBFIFO%d:", unit); |
486 | nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show); | 501 | nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show); |
487 | printk("\n"); | 502 | pr_cont("\n"); |
488 | nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x " | 503 | nv_error(priv, |
489 | "data 0x%08x\n", | 504 | "SUBFIFO%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", |
490 | unit, chid, subc, mthd, data); | 505 | unit, chid, |
506 | nouveau_client_name_for_fifo_chid(&priv->base, chid), | ||
507 | subc, mthd, data); | ||
491 | } | 508 | } |
492 | 509 | ||
493 | nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); | 510 | nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); |
@@ -501,12 +518,34 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev) | |||
501 | u32 mask = nv_rd32(priv, 0x002140); | 518 | u32 mask = nv_rd32(priv, 0x002140); |
502 | u32 stat = nv_rd32(priv, 0x002100) & mask; | 519 | u32 stat = nv_rd32(priv, 0x002100) & mask; |
503 | 520 | ||
521 | if (stat & 0x00000001) { | ||
522 | u32 intr = nv_rd32(priv, 0x00252c); | ||
523 | nv_warn(priv, "INTR 0x00000001: 0x%08x\n", intr); | ||
524 | nv_wr32(priv, 0x002100, 0x00000001); | ||
525 | stat &= ~0x00000001; | ||
526 | } | ||
527 | |||
504 | if (stat & 0x00000100) { | 528 | if (stat & 0x00000100) { |
505 | nv_warn(priv, "unknown status 0x00000100\n"); | 529 | u32 intr = nv_rd32(priv, 0x00254c); |
530 | nv_warn(priv, "INTR 0x00000100: 0x%08x\n", intr); | ||
506 | nv_wr32(priv, 0x002100, 0x00000100); | 531 | nv_wr32(priv, 0x002100, 0x00000100); |
507 | stat &= ~0x00000100; | 532 | stat &= ~0x00000100; |
508 | } | 533 | } |
509 | 534 | ||
535 | if (stat & 0x00010000) { | ||
536 | u32 intr = nv_rd32(priv, 0x00256c); | ||
537 | nv_warn(priv, "INTR 0x00010000: 0x%08x\n", intr); | ||
538 | nv_wr32(priv, 0x002100, 0x00010000); | ||
539 | stat &= ~0x00010000; | ||
540 | } | ||
541 | |||
542 | if (stat & 0x01000000) { | ||
543 | u32 intr = nv_rd32(priv, 0x00258c); | ||
544 | nv_warn(priv, "INTR 0x01000000: 0x%08x\n", intr); | ||
545 | nv_wr32(priv, 0x002100, 0x01000000); | ||
546 | stat &= ~0x01000000; | ||
547 | } | ||
548 | |||
510 | if (stat & 0x10000000) { | 549 | if (stat & 0x10000000) { |
511 | u32 units = nv_rd32(priv, 0x00259c); | 550 | u32 units = nv_rd32(priv, 0x00259c); |
512 | u32 u = units; | 551 | u32 u = units; |
@@ -536,11 +575,20 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev) | |||
536 | } | 575 | } |
537 | 576 | ||
538 | if (stat & 0x40000000) { | 577 | if (stat & 0x40000000) { |
539 | nv_warn(priv, "unknown status 0x40000000\n"); | 578 | u32 intr0 = nv_rd32(priv, 0x0025a4); |
540 | nv_mask(priv, 0x002a00, 0x00000000, 0x00000000); | 579 | u32 intr1 = nv_mask(priv, 0x002a00, 0x00000000, 0x00000); |
580 | nv_debug(priv, "INTR 0x40000000: 0x%08x 0x%08x\n", | ||
581 | intr0, intr1); | ||
541 | stat &= ~0x40000000; | 582 | stat &= ~0x40000000; |
542 | } | 583 | } |
543 | 584 | ||
585 | if (stat & 0x80000000) { | ||
586 | u32 intr = nv_mask(priv, 0x0025a8, 0x00000000, 0x00000000); | ||
587 | nouveau_event_trigger(priv->base.uevent, 0); | ||
588 | nv_debug(priv, "INTR 0x80000000: 0x%08x\n", intr); | ||
589 | stat &= ~0x80000000; | ||
590 | } | ||
591 | |||
544 | if (stat) { | 592 | if (stat) { |
545 | nv_fatal(priv, "unhandled status 0x%08x\n", stat); | 593 | nv_fatal(priv, "unhandled status 0x%08x\n", stat); |
546 | nv_wr32(priv, 0x002100, stat); | 594 | nv_wr32(priv, 0x002100, stat); |
@@ -548,6 +596,20 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev) | |||
548 | } | 596 | } |
549 | } | 597 | } |
550 | 598 | ||
599 | static void | ||
600 | nvc0_fifo_uevent_enable(struct nouveau_event *event, int index) | ||
601 | { | ||
602 | struct nvc0_fifo_priv *priv = event->priv; | ||
603 | nv_mask(priv, 0x002140, 0x80000000, 0x80000000); | ||
604 | } | ||
605 | |||
606 | static void | ||
607 | nvc0_fifo_uevent_disable(struct nouveau_event *event, int index) | ||
608 | { | ||
609 | struct nvc0_fifo_priv *priv = event->priv; | ||
610 | nv_mask(priv, 0x002140, 0x80000000, 0x00000000); | ||
611 | } | ||
612 | |||
551 | static int | 613 | static int |
552 | nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 614 | nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
553 | struct nouveau_oclass *oclass, void *data, u32 size, | 615 | struct nouveau_oclass *oclass, void *data, u32 size, |
@@ -581,6 +643,10 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
581 | if (ret) | 643 | if (ret) |
582 | return ret; | 644 | return ret; |
583 | 645 | ||
646 | priv->base.uevent->enable = nvc0_fifo_uevent_enable; | ||
647 | priv->base.uevent->disable = nvc0_fifo_uevent_disable; | ||
648 | priv->base.uevent->priv = priv; | ||
649 | |||
584 | nv_subdev(priv)->unit = 0x00000100; | 650 | nv_subdev(priv)->unit = 0x00000100; |
585 | nv_subdev(priv)->intr = nvc0_fifo_intr; | 651 | nv_subdev(priv)->intr = nvc0_fifo_intr; |
586 | nv_engine(priv)->cclass = &nvc0_fifo_cclass; | 652 | nv_engine(priv)->cclass = &nvc0_fifo_cclass; |
@@ -639,7 +705,8 @@ nvc0_fifo_init(struct nouveau_object *object) | |||
639 | 705 | ||
640 | nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */ | 706 | nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */ |
641 | nv_wr32(priv, 0x002100, 0xffffffff); | 707 | nv_wr32(priv, 0x002100, 0xffffffff); |
642 | nv_wr32(priv, 0x002140, 0xbfffffff); | 708 | nv_wr32(priv, 0x002140, 0x3fffffff); |
709 | nv_wr32(priv, 0x002628, 0x00000001); /* makes mthd 0x20 work */ | ||
643 | return 0; | 710 | return 0; |
644 | } | 711 | } |
645 | 712 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index c930da99c2c1..4419e40d88e9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <core/namedb.h> | 27 | #include <core/namedb.h> |
28 | #include <core/gpuobj.h> | 28 | #include <core/gpuobj.h> |
29 | #include <core/engctx.h> | 29 | #include <core/engctx.h> |
30 | #include <core/event.h> | ||
30 | #include <core/class.h> | 31 | #include <core/class.h> |
31 | #include <core/math.h> | 32 | #include <core/math.h> |
32 | #include <core/enum.h> | 33 | #include <core/enum.h> |
@@ -184,7 +185,8 @@ nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend, | |||
184 | 185 | ||
185 | nv_wr32(priv, 0x002634, chan->base.chid); | 186 | nv_wr32(priv, 0x002634, chan->base.chid); |
186 | if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { | 187 | if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { |
187 | nv_error(priv, "channel %d kick timeout\n", chan->base.chid); | 188 | nv_error(priv, "channel %d [%s] kick timeout\n", |
189 | chan->base.chid, nouveau_client_name(chan)); | ||
188 | if (suspend) | 190 | if (suspend) |
189 | return -EBUSY; | 191 | return -EBUSY; |
190 | } | 192 | } |
@@ -412,20 +414,34 @@ nve0_fifo_isr_vm_fault(struct nve0_fifo_priv *priv, int unit) | |||
412 | u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10)); | 414 | u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10)); |
413 | u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10)); | 415 | u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10)); |
414 | u32 client = (stat & 0x00001f00) >> 8; | 416 | u32 client = (stat & 0x00001f00) >> 8; |
417 | const struct nouveau_enum *en; | ||
418 | struct nouveau_engine *engine; | ||
419 | struct nouveau_object *engctx = NULL; | ||
415 | 420 | ||
416 | nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ? | 421 | nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ? |
417 | "write" : "read", (u64)vahi << 32 | valo); | 422 | "write" : "read", (u64)vahi << 32 | valo); |
418 | nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f); | 423 | nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f); |
419 | printk("] from "); | 424 | pr_cont("] from "); |
420 | nouveau_enum_print(nve0_fifo_fault_unit, unit); | 425 | en = nouveau_enum_print(nve0_fifo_fault_unit, unit); |
421 | if (stat & 0x00000040) { | 426 | if (stat & 0x00000040) { |
422 | printk("/"); | 427 | pr_cont("/"); |
423 | nouveau_enum_print(nve0_fifo_fault_hubclient, client); | 428 | nouveau_enum_print(nve0_fifo_fault_hubclient, client); |
424 | } else { | 429 | } else { |
425 | printk("/GPC%d/", (stat & 0x1f000000) >> 24); | 430 | pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24); |
426 | nouveau_enum_print(nve0_fifo_fault_gpcclient, client); | 431 | nouveau_enum_print(nve0_fifo_fault_gpcclient, client); |
427 | } | 432 | } |
428 | printk(" on channel 0x%010llx\n", (u64)inst << 12); | 433 | |
434 | if (en && en->data2) { | ||
435 | engine = nouveau_engine(priv, en->data2); | ||
436 | if (engine) | ||
437 | engctx = nouveau_engctx_get(engine, inst); | ||
438 | |||
439 | } | ||
440 | |||
441 | pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12, | ||
442 | nouveau_client_name(engctx)); | ||
443 | |||
444 | nouveau_engctx_put(engctx); | ||
429 | } | 445 | } |
430 | 446 | ||
431 | static int | 447 | static int |
@@ -480,10 +496,12 @@ nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit) | |||
480 | if (show) { | 496 | if (show) { |
481 | nv_error(priv, "SUBFIFO%d:", unit); | 497 | nv_error(priv, "SUBFIFO%d:", unit); |
482 | nouveau_bitfield_print(nve0_fifo_subfifo_intr, show); | 498 | nouveau_bitfield_print(nve0_fifo_subfifo_intr, show); |
483 | printk("\n"); | 499 | pr_cont("\n"); |
484 | nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x " | 500 | nv_error(priv, |
485 | "data 0x%08x\n", | 501 | "SUBFIFO%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", |
486 | unit, chid, subc, mthd, data); | 502 | unit, chid, |
503 | nouveau_client_name_for_fifo_chid(&priv->base, chid), | ||
504 | subc, mthd, data); | ||
487 | } | 505 | } |
488 | 506 | ||
489 | nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); | 507 | nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); |
@@ -537,6 +555,12 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) | |||
537 | stat &= ~0x40000000; | 555 | stat &= ~0x40000000; |
538 | } | 556 | } |
539 | 557 | ||
558 | if (stat & 0x80000000) { | ||
559 | nouveau_event_trigger(priv->base.uevent, 0); | ||
560 | nv_wr32(priv, 0x002100, 0x80000000); | ||
561 | stat &= ~0x80000000; | ||
562 | } | ||
563 | |||
540 | if (stat) { | 564 | if (stat) { |
541 | nv_fatal(priv, "unhandled status 0x%08x\n", stat); | 565 | nv_fatal(priv, "unhandled status 0x%08x\n", stat); |
542 | nv_wr32(priv, 0x002100, stat); | 566 | nv_wr32(priv, 0x002100, stat); |
@@ -544,6 +568,20 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) | |||
544 | } | 568 | } |
545 | } | 569 | } |
546 | 570 | ||
571 | static void | ||
572 | nve0_fifo_uevent_enable(struct nouveau_event *event, int index) | ||
573 | { | ||
574 | struct nve0_fifo_priv *priv = event->priv; | ||
575 | nv_mask(priv, 0x002140, 0x80000000, 0x80000000); | ||
576 | } | ||
577 | |||
578 | static void | ||
579 | nve0_fifo_uevent_disable(struct nouveau_event *event, int index) | ||
580 | { | ||
581 | struct nve0_fifo_priv *priv = event->priv; | ||
582 | nv_mask(priv, 0x002140, 0x80000000, 0x00000000); | ||
583 | } | ||
584 | |||
547 | static int | 585 | static int |
548 | nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 586 | nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
549 | struct nouveau_oclass *oclass, void *data, u32 size, | 587 | struct nouveau_oclass *oclass, void *data, u32 size, |
@@ -567,6 +605,10 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
567 | if (ret) | 605 | if (ret) |
568 | return ret; | 606 | return ret; |
569 | 607 | ||
608 | priv->base.uevent->enable = nve0_fifo_uevent_enable; | ||
609 | priv->base.uevent->disable = nve0_fifo_uevent_disable; | ||
610 | priv->base.uevent->priv = priv; | ||
611 | |||
570 | nv_subdev(priv)->unit = 0x00000100; | 612 | nv_subdev(priv)->unit = 0x00000100; |
571 | nv_subdev(priv)->intr = nve0_fifo_intr; | 613 | nv_subdev(priv)->intr = nve0_fifo_intr; |
572 | nv_engine(priv)->cclass = &nve0_fifo_cclass; | 614 | nv_engine(priv)->cclass = &nve0_fifo_cclass; |
@@ -617,7 +659,7 @@ nve0_fifo_init(struct nouveau_object *object) | |||
617 | 659 | ||
618 | nv_wr32(priv, 0x002a00, 0xffffffff); | 660 | nv_wr32(priv, 0x002a00, 0xffffffff); |
619 | nv_wr32(priv, 0x002100, 0xffffffff); | 661 | nv_wr32(priv, 0x002100, 0xffffffff); |
620 | nv_wr32(priv, 0x002140, 0xbfffffff); | 662 | nv_wr32(priv, 0x002140, 0x3fffffff); |
621 | return 0; | 663 | return 0; |
622 | } | 664 | } |
623 | 665 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c index e30a9c5ff1fc..ad13dcdd15f9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * DEALINGS IN THE SOFTWARE. | 22 | * DEALINGS IN THE SOFTWARE. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/client.h> | ||
25 | #include <core/os.h> | 26 | #include <core/os.h> |
26 | #include <core/class.h> | 27 | #include <core/class.h> |
27 | #include <core/handle.h> | 28 | #include <core/handle.h> |
@@ -1297,16 +1298,17 @@ nv04_graph_intr(struct nouveau_subdev *subdev) | |||
1297 | nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); | 1298 | nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); |
1298 | 1299 | ||
1299 | if (show) { | 1300 | if (show) { |
1300 | nv_error(priv, ""); | 1301 | nv_error(priv, "%s", ""); |
1301 | nouveau_bitfield_print(nv04_graph_intr_name, show); | 1302 | nouveau_bitfield_print(nv04_graph_intr_name, show); |
1302 | printk(" nsource:"); | 1303 | pr_cont(" nsource:"); |
1303 | nouveau_bitfield_print(nv04_graph_nsource, nsource); | 1304 | nouveau_bitfield_print(nv04_graph_nsource, nsource); |
1304 | printk(" nstatus:"); | 1305 | pr_cont(" nstatus:"); |
1305 | nouveau_bitfield_print(nv04_graph_nstatus, nstatus); | 1306 | nouveau_bitfield_print(nv04_graph_nstatus, nstatus); |
1306 | printk("\n"); | 1307 | pr_cont("\n"); |
1307 | nv_error(priv, "ch %d/%d class 0x%04x " | 1308 | nv_error(priv, |
1308 | "mthd 0x%04x data 0x%08x\n", | 1309 | "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
1309 | chid, subc, class, mthd, data); | 1310 | chid, nouveau_client_name(chan), subc, class, mthd, |
1311 | data); | ||
1310 | } | 1312 | } |
1311 | 1313 | ||
1312 | nouveau_namedb_put(handle); | 1314 | nouveau_namedb_put(handle); |
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c index 5c0f843ea249..23c143aaa556 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * DEALINGS IN THE SOFTWARE. | 22 | * DEALINGS IN THE SOFTWARE. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/client.h> | ||
25 | #include <core/os.h> | 26 | #include <core/os.h> |
26 | #include <core/class.h> | 27 | #include <core/class.h> |
27 | #include <core/handle.h> | 28 | #include <core/handle.h> |
@@ -1193,16 +1194,17 @@ nv10_graph_intr(struct nouveau_subdev *subdev) | |||
1193 | nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); | 1194 | nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); |
1194 | 1195 | ||
1195 | if (show) { | 1196 | if (show) { |
1196 | nv_error(priv, ""); | 1197 | nv_error(priv, "%s", ""); |
1197 | nouveau_bitfield_print(nv10_graph_intr_name, show); | 1198 | nouveau_bitfield_print(nv10_graph_intr_name, show); |
1198 | printk(" nsource:"); | 1199 | pr_cont(" nsource:"); |
1199 | nouveau_bitfield_print(nv04_graph_nsource, nsource); | 1200 | nouveau_bitfield_print(nv04_graph_nsource, nsource); |
1200 | printk(" nstatus:"); | 1201 | pr_cont(" nstatus:"); |
1201 | nouveau_bitfield_print(nv10_graph_nstatus, nstatus); | 1202 | nouveau_bitfield_print(nv10_graph_nstatus, nstatus); |
1202 | printk("\n"); | 1203 | pr_cont("\n"); |
1203 | nv_error(priv, "ch %d/%d class 0x%04x " | 1204 | nv_error(priv, |
1204 | "mthd 0x%04x data 0x%08x\n", | 1205 | "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
1205 | chid, subc, class, mthd, data); | 1206 | chid, nouveau_client_name(chan), subc, class, mthd, |
1207 | data); | ||
1206 | } | 1208 | } |
1207 | 1209 | ||
1208 | nouveau_namedb_put(handle); | 1210 | nouveau_namedb_put(handle); |
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c index 5b20401bf911..0607b9801748 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <core/client.h> | ||
1 | #include <core/os.h> | 2 | #include <core/os.h> |
2 | #include <core/class.h> | 3 | #include <core/class.h> |
3 | #include <core/engctx.h> | 4 | #include <core/engctx.h> |
@@ -224,15 +225,17 @@ nv20_graph_intr(struct nouveau_subdev *subdev) | |||
224 | nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); | 225 | nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); |
225 | 226 | ||
226 | if (show) { | 227 | if (show) { |
227 | nv_error(priv, ""); | 228 | nv_error(priv, "%s", ""); |
228 | nouveau_bitfield_print(nv10_graph_intr_name, show); | 229 | nouveau_bitfield_print(nv10_graph_intr_name, show); |
229 | printk(" nsource:"); | 230 | pr_cont(" nsource:"); |
230 | nouveau_bitfield_print(nv04_graph_nsource, nsource); | 231 | nouveau_bitfield_print(nv04_graph_nsource, nsource); |
231 | printk(" nstatus:"); | 232 | pr_cont(" nstatus:"); |
232 | nouveau_bitfield_print(nv10_graph_nstatus, nstatus); | 233 | nouveau_bitfield_print(nv10_graph_nstatus, nstatus); |
233 | printk("\n"); | 234 | pr_cont("\n"); |
234 | nv_error(priv, "ch %d/%d class 0x%04x mthd 0x%04x data 0x%08x\n", | 235 | nv_error(priv, |
235 | chid, subc, class, mthd, data); | 236 | "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
237 | chid, nouveau_client_name(engctx), subc, class, mthd, | ||
238 | data); | ||
236 | } | 239 | } |
237 | 240 | ||
238 | nouveau_engctx_put(engctx); | 241 | nouveau_engctx_put(engctx); |
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 0b36dd3deebd..17049d5c723d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/client.h> | ||
25 | #include <core/os.h> | 26 | #include <core/os.h> |
26 | #include <core/class.h> | 27 | #include <core/class.h> |
27 | #include <core/handle.h> | 28 | #include <core/handle.h> |
@@ -321,16 +322,17 @@ nv40_graph_intr(struct nouveau_subdev *subdev) | |||
321 | nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); | 322 | nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); |
322 | 323 | ||
323 | if (show) { | 324 | if (show) { |
324 | nv_error(priv, ""); | 325 | nv_error(priv, "%s", ""); |
325 | nouveau_bitfield_print(nv10_graph_intr_name, show); | 326 | nouveau_bitfield_print(nv10_graph_intr_name, show); |
326 | printk(" nsource:"); | 327 | pr_cont(" nsource:"); |
327 | nouveau_bitfield_print(nv04_graph_nsource, nsource); | 328 | nouveau_bitfield_print(nv04_graph_nsource, nsource); |
328 | printk(" nstatus:"); | 329 | pr_cont(" nstatus:"); |
329 | nouveau_bitfield_print(nv10_graph_nstatus, nstatus); | 330 | nouveau_bitfield_print(nv10_graph_nstatus, nstatus); |
330 | printk("\n"); | 331 | pr_cont("\n"); |
331 | nv_error(priv, "ch %d [0x%08x] subc %d class 0x%04x " | 332 | nv_error(priv, |
332 | "mthd 0x%04x data 0x%08x\n", | 333 | "ch %d [0x%08x %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
333 | chid, inst << 4, subc, class, mthd, data); | 334 | chid, inst << 4, nouveau_client_name(engctx), subc, |
335 | class, mthd, data); | ||
334 | } | 336 | } |
335 | 337 | ||
336 | nouveau_engctx_put(engctx); | 338 | nouveau_engctx_put(engctx); |
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c index b1c3d835b4c2..f2b1a7a124f2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <core/os.h> | 25 | #include <core/os.h> |
26 | #include <core/class.h> | 26 | #include <core/class.h> |
27 | #include <core/client.h> | ||
27 | #include <core/handle.h> | 28 | #include <core/handle.h> |
28 | #include <core/engctx.h> | 29 | #include <core/engctx.h> |
29 | #include <core/enum.h> | 30 | #include <core/enum.h> |
@@ -418,7 +419,7 @@ nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display) | |||
418 | nv_error(priv, "TRAP_MP_EXEC - " | 419 | nv_error(priv, "TRAP_MP_EXEC - " |
419 | "TP %d MP %d: ", tpid, i); | 420 | "TP %d MP %d: ", tpid, i); |
420 | nouveau_enum_print(nv50_mp_exec_error_names, status); | 421 | nouveau_enum_print(nv50_mp_exec_error_names, status); |
421 | printk(" at %06x warp %d, opcode %08x %08x\n", | 422 | pr_cont(" at %06x warp %d, opcode %08x %08x\n", |
422 | pc&0xffffff, pc >> 24, | 423 | pc&0xffffff, pc >> 24, |
423 | oplow, ophigh); | 424 | oplow, ophigh); |
424 | } | 425 | } |
@@ -532,7 +533,7 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old, | |||
532 | 533 | ||
533 | static int | 534 | static int |
534 | nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, | 535 | nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, |
535 | int chid, u64 inst) | 536 | int chid, u64 inst, struct nouveau_object *engctx) |
536 | { | 537 | { |
537 | u32 status = nv_rd32(priv, 0x400108); | 538 | u32 status = nv_rd32(priv, 0x400108); |
538 | u32 ustatus; | 539 | u32 ustatus; |
@@ -565,12 +566,11 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, | |||
565 | 566 | ||
566 | nv_error(priv, "TRAP DISPATCH_FAULT\n"); | 567 | nv_error(priv, "TRAP DISPATCH_FAULT\n"); |
567 | if (display && (addr & 0x80000000)) { | 568 | if (display && (addr & 0x80000000)) { |
568 | nv_error(priv, "ch %d [0x%010llx] " | 569 | nv_error(priv, |
569 | "subc %d class 0x%04x mthd 0x%04x " | 570 | "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x%08x 400808 0x%08x 400848 0x%08x\n", |
570 | "data 0x%08x%08x " | 571 | chid, inst, |
571 | "400808 0x%08x 400848 0x%08x\n", | 572 | nouveau_client_name(engctx), subc, |
572 | chid, inst, subc, class, mthd, datah, | 573 | class, mthd, datah, datal, addr, r848); |
573 | datal, addr, r848); | ||
574 | } else | 574 | } else |
575 | if (display) { | 575 | if (display) { |
576 | nv_error(priv, "no stuck command?\n"); | 576 | nv_error(priv, "no stuck command?\n"); |
@@ -591,11 +591,11 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, | |||
591 | 591 | ||
592 | nv_error(priv, "TRAP DISPATCH_QUERY\n"); | 592 | nv_error(priv, "TRAP DISPATCH_QUERY\n"); |
593 | if (display && (addr & 0x80000000)) { | 593 | if (display && (addr & 0x80000000)) { |
594 | nv_error(priv, "ch %d [0x%010llx] " | 594 | nv_error(priv, |
595 | "subc %d class 0x%04x mthd 0x%04x " | 595 | "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x 40084c 0x%08x\n", |
596 | "data 0x%08x 40084c 0x%08x\n", | 596 | chid, inst, |
597 | chid, inst, subc, class, mthd, | 597 | nouveau_client_name(engctx), subc, |
598 | data, addr); | 598 | class, mthd, data, addr); |
599 | } else | 599 | } else |
600 | if (display) { | 600 | if (display) { |
601 | nv_error(priv, "no stuck command?\n"); | 601 | nv_error(priv, "no stuck command?\n"); |
@@ -623,7 +623,7 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, | |||
623 | if (display) { | 623 | if (display) { |
624 | nv_error(priv, "TRAP_M2MF"); | 624 | nv_error(priv, "TRAP_M2MF"); |
625 | nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus); | 625 | nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus); |
626 | printk("\n"); | 626 | pr_cont("\n"); |
627 | nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n", | 627 | nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n", |
628 | nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808), | 628 | nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808), |
629 | nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810)); | 629 | nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810)); |
@@ -644,7 +644,7 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, | |||
644 | if (display) { | 644 | if (display) { |
645 | nv_error(priv, "TRAP_VFETCH"); | 645 | nv_error(priv, "TRAP_VFETCH"); |
646 | nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus); | 646 | nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus); |
647 | printk("\n"); | 647 | pr_cont("\n"); |
648 | nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n", | 648 | nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n", |
649 | nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08), | 649 | nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08), |
650 | nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10)); | 650 | nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10)); |
@@ -661,7 +661,7 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, | |||
661 | if (display) { | 661 | if (display) { |
662 | nv_error(priv, "TRAP_STRMOUT"); | 662 | nv_error(priv, "TRAP_STRMOUT"); |
663 | nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus); | 663 | nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus); |
664 | printk("\n"); | 664 | pr_cont("\n"); |
665 | nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n", | 665 | nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n", |
666 | nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808), | 666 | nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808), |
667 | nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810)); | 667 | nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810)); |
@@ -682,7 +682,7 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, | |||
682 | if (display) { | 682 | if (display) { |
683 | nv_error(priv, "TRAP_CCACHE"); | 683 | nv_error(priv, "TRAP_CCACHE"); |
684 | nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus); | 684 | nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus); |
685 | printk("\n"); | 685 | pr_cont("\n"); |
686 | nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x" | 686 | nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x" |
687 | " %08x %08x %08x\n", | 687 | " %08x %08x %08x\n", |
688 | nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004), | 688 | nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004), |
@@ -774,11 +774,12 @@ nv50_graph_intr(struct nouveau_subdev *subdev) | |||
774 | u32 ecode = nv_rd32(priv, 0x400110); | 774 | u32 ecode = nv_rd32(priv, 0x400110); |
775 | nv_error(priv, "DATA_ERROR "); | 775 | nv_error(priv, "DATA_ERROR "); |
776 | nouveau_enum_print(nv50_data_error_names, ecode); | 776 | nouveau_enum_print(nv50_data_error_names, ecode); |
777 | printk("\n"); | 777 | pr_cont("\n"); |
778 | } | 778 | } |
779 | 779 | ||
780 | if (stat & 0x00200000) { | 780 | if (stat & 0x00200000) { |
781 | if (!nv50_graph_trap_handler(priv, show, chid, (u64)inst << 12)) | 781 | if (!nv50_graph_trap_handler(priv, show, chid, (u64)inst << 12, |
782 | engctx)) | ||
782 | show &= ~0x00200000; | 783 | show &= ~0x00200000; |
783 | } | 784 | } |
784 | 785 | ||
@@ -786,12 +787,13 @@ nv50_graph_intr(struct nouveau_subdev *subdev) | |||
786 | nv_wr32(priv, 0x400500, 0x00010001); | 787 | nv_wr32(priv, 0x400500, 0x00010001); |
787 | 788 | ||
788 | if (show) { | 789 | if (show) { |
789 | nv_error(priv, ""); | 790 | nv_error(priv, "%s", ""); |
790 | nouveau_bitfield_print(nv50_graph_intr_name, show); | 791 | nouveau_bitfield_print(nv50_graph_intr_name, show); |
791 | printk("\n"); | 792 | pr_cont("\n"); |
792 | nv_error(priv, "ch %d [0x%010llx] subc %d class 0x%04x " | 793 | nv_error(priv, |
793 | "mthd 0x%04x data 0x%08x\n", | 794 | "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
794 | chid, (u64)inst << 12, subc, class, mthd, data); | 795 | chid, (u64)inst << 12, nouveau_client_name(engctx), |
796 | subc, class, mthd, data); | ||
795 | } | 797 | } |
796 | 798 | ||
797 | if (nv_rd32(priv, 0x400824) & (1 << 31)) | 799 | if (nv_rd32(priv, 0x400824) & (1 << 31)) |
@@ -907,9 +909,8 @@ nv50_graph_init(struct nouveau_object *object) | |||
907 | nv_wr32(priv, 0x400828, 0x00000000); | 909 | nv_wr32(priv, 0x400828, 0x00000000); |
908 | nv_wr32(priv, 0x40082c, 0x00000000); | 910 | nv_wr32(priv, 0x40082c, 0x00000000); |
909 | nv_wr32(priv, 0x400830, 0x00000000); | 911 | nv_wr32(priv, 0x400830, 0x00000000); |
910 | nv_wr32(priv, 0x400724, 0x00000000); | ||
911 | nv_wr32(priv, 0x40032c, 0x00000000); | 912 | nv_wr32(priv, 0x40032c, 0x00000000); |
912 | nv_wr32(priv, 0x400320, 4); /* CTXCTL_CMD = NEWCTXDMA */ | 913 | nv_wr32(priv, 0x400330, 0x00000000); |
913 | 914 | ||
914 | /* some unknown zcull magic */ | 915 | /* some unknown zcull magic */ |
915 | switch (nv_device(priv)->chipset & 0xf0) { | 916 | switch (nv_device(priv)->chipset & 0xf0) { |
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c index 45aff5f5085a..0de0dd724aff 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c | |||
@@ -433,10 +433,10 @@ nvc0_graph_intr(struct nouveau_subdev *subdev) | |||
433 | if (stat & 0x00000010) { | 433 | if (stat & 0x00000010) { |
434 | handle = nouveau_handle_get_class(engctx, class); | 434 | handle = nouveau_handle_get_class(engctx, class); |
435 | if (!handle || nv_call(handle->object, mthd, data)) { | 435 | if (!handle || nv_call(handle->object, mthd, data)) { |
436 | nv_error(priv, "ILLEGAL_MTHD ch %d [0x%010llx] " | 436 | nv_error(priv, |
437 | "subc %d class 0x%04x mthd 0x%04x " | 437 | "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
438 | "data 0x%08x\n", | 438 | chid, inst << 12, nouveau_client_name(engctx), |
439 | chid, inst << 12, subc, class, mthd, data); | 439 | subc, class, mthd, data); |
440 | } | 440 | } |
441 | nouveau_handle_put(handle); | 441 | nouveau_handle_put(handle); |
442 | nv_wr32(priv, 0x400100, 0x00000010); | 442 | nv_wr32(priv, 0x400100, 0x00000010); |
@@ -444,9 +444,10 @@ nvc0_graph_intr(struct nouveau_subdev *subdev) | |||
444 | } | 444 | } |
445 | 445 | ||
446 | if (stat & 0x00000020) { | 446 | if (stat & 0x00000020) { |
447 | nv_error(priv, "ILLEGAL_CLASS ch %d [0x%010llx] subc %d " | 447 | nv_error(priv, |
448 | "class 0x%04x mthd 0x%04x data 0x%08x\n", | 448 | "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
449 | chid, inst << 12, subc, class, mthd, data); | 449 | chid, inst << 12, nouveau_client_name(engctx), subc, |
450 | class, mthd, data); | ||
450 | nv_wr32(priv, 0x400100, 0x00000020); | 451 | nv_wr32(priv, 0x400100, 0x00000020); |
451 | stat &= ~0x00000020; | 452 | stat &= ~0x00000020; |
452 | } | 453 | } |
@@ -454,15 +455,16 @@ nvc0_graph_intr(struct nouveau_subdev *subdev) | |||
454 | if (stat & 0x00100000) { | 455 | if (stat & 0x00100000) { |
455 | nv_error(priv, "DATA_ERROR ["); | 456 | nv_error(priv, "DATA_ERROR ["); |
456 | nouveau_enum_print(nv50_data_error_names, code); | 457 | nouveau_enum_print(nv50_data_error_names, code); |
457 | printk("] ch %d [0x%010llx] subc %d class 0x%04x " | 458 | pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
458 | "mthd 0x%04x data 0x%08x\n", | 459 | chid, inst << 12, nouveau_client_name(engctx), subc, |
459 | chid, inst << 12, subc, class, mthd, data); | 460 | class, mthd, data); |
460 | nv_wr32(priv, 0x400100, 0x00100000); | 461 | nv_wr32(priv, 0x400100, 0x00100000); |
461 | stat &= ~0x00100000; | 462 | stat &= ~0x00100000; |
462 | } | 463 | } |
463 | 464 | ||
464 | if (stat & 0x00200000) { | 465 | if (stat & 0x00200000) { |
465 | nv_error(priv, "TRAP ch %d [0x%010llx]\n", chid, inst << 12); | 466 | nv_error(priv, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12, |
467 | nouveau_client_name(engctx)); | ||
466 | nvc0_graph_trap_intr(priv); | 468 | nvc0_graph_trap_intr(priv); |
467 | nv_wr32(priv, 0x400100, 0x00200000); | 469 | nv_wr32(priv, 0x400100, 0x00200000); |
468 | stat &= ~0x00200000; | 470 | stat &= ~0x00200000; |
@@ -611,10 +613,8 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
611 | static void | 613 | static void |
612 | nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc) | 614 | nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc) |
613 | { | 615 | { |
614 | if (fuc->data) { | 616 | kfree(fuc->data); |
615 | kfree(fuc->data); | 617 | fuc->data = NULL; |
616 | fuc->data = NULL; | ||
617 | } | ||
618 | } | 618 | } |
619 | 619 | ||
620 | void | 620 | void |
@@ -622,8 +622,7 @@ nvc0_graph_dtor(struct nouveau_object *object) | |||
622 | { | 622 | { |
623 | struct nvc0_graph_priv *priv = (void *)object; | 623 | struct nvc0_graph_priv *priv = (void *)object; |
624 | 624 | ||
625 | if (priv->data) | 625 | kfree(priv->data); |
626 | kfree(priv->data); | ||
627 | 626 | ||
628 | nvc0_graph_dtor_fw(&priv->fuc409c); | 627 | nvc0_graph_dtor_fw(&priv->fuc409c); |
629 | nvc0_graph_dtor_fw(&priv->fuc409d); | 628 | nvc0_graph_dtor_fw(&priv->fuc409d); |
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c index 9f82e9702b46..61cec0f6ff1c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c | |||
@@ -78,15 +78,16 @@ nve0_graph_ctxctl_isr(struct nvc0_graph_priv *priv) | |||
78 | } | 78 | } |
79 | 79 | ||
80 | static void | 80 | static void |
81 | nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst) | 81 | nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst, |
82 | struct nouveau_object *engctx) | ||
82 | { | 83 | { |
83 | u32 trap = nv_rd32(priv, 0x400108); | 84 | u32 trap = nv_rd32(priv, 0x400108); |
84 | int rop; | 85 | int rop; |
85 | 86 | ||
86 | if (trap & 0x00000001) { | 87 | if (trap & 0x00000001) { |
87 | u32 stat = nv_rd32(priv, 0x404000); | 88 | u32 stat = nv_rd32(priv, 0x404000); |
88 | nv_error(priv, "DISPATCH ch %d [0x%010llx] 0x%08x\n", | 89 | nv_error(priv, "DISPATCH ch %d [0x%010llx %s] 0x%08x\n", |
89 | chid, inst, stat); | 90 | chid, inst, nouveau_client_name(engctx), stat); |
90 | nv_wr32(priv, 0x404000, 0xc0000000); | 91 | nv_wr32(priv, 0x404000, 0xc0000000); |
91 | nv_wr32(priv, 0x400108, 0x00000001); | 92 | nv_wr32(priv, 0x400108, 0x00000001); |
92 | trap &= ~0x00000001; | 93 | trap &= ~0x00000001; |
@@ -94,8 +95,8 @@ nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst) | |||
94 | 95 | ||
95 | if (trap & 0x00000010) { | 96 | if (trap & 0x00000010) { |
96 | u32 stat = nv_rd32(priv, 0x405840); | 97 | u32 stat = nv_rd32(priv, 0x405840); |
97 | nv_error(priv, "SHADER ch %d [0x%010llx] 0x%08x\n", | 98 | nv_error(priv, "SHADER ch %d [0x%010llx %s] 0x%08x\n", |
98 | chid, inst, stat); | 99 | chid, inst, nouveau_client_name(engctx), stat); |
99 | nv_wr32(priv, 0x405840, 0xc0000000); | 100 | nv_wr32(priv, 0x405840, 0xc0000000); |
100 | nv_wr32(priv, 0x400108, 0x00000010); | 101 | nv_wr32(priv, 0x400108, 0x00000010); |
101 | trap &= ~0x00000010; | 102 | trap &= ~0x00000010; |
@@ -105,8 +106,10 @@ nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst) | |||
105 | for (rop = 0; rop < priv->rop_nr; rop++) { | 106 | for (rop = 0; rop < priv->rop_nr; rop++) { |
106 | u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070)); | 107 | u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070)); |
107 | u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144)); | 108 | u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144)); |
108 | nv_error(priv, "ROP%d ch %d [0x%010llx] 0x%08x 0x%08x\n", | 109 | nv_error(priv, |
109 | rop, chid, inst, statz, statc); | 110 | "ROP%d ch %d [0x%010llx %s] 0x%08x 0x%08x\n", |
111 | rop, chid, inst, nouveau_client_name(engctx), | ||
112 | statz, statc); | ||
110 | nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); | 113 | nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); |
111 | nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); | 114 | nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); |
112 | } | 115 | } |
@@ -115,8 +118,8 @@ nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst) | |||
115 | } | 118 | } |
116 | 119 | ||
117 | if (trap) { | 120 | if (trap) { |
118 | nv_error(priv, "TRAP ch %d [0x%010llx] 0x%08x\n", | 121 | nv_error(priv, "TRAP ch %d [0x%010llx %s] 0x%08x\n", |
119 | chid, inst, trap); | 122 | chid, inst, nouveau_client_name(engctx), trap); |
120 | nv_wr32(priv, 0x400108, trap); | 123 | nv_wr32(priv, 0x400108, trap); |
121 | } | 124 | } |
122 | } | 125 | } |
@@ -145,10 +148,10 @@ nve0_graph_intr(struct nouveau_subdev *subdev) | |||
145 | if (stat & 0x00000010) { | 148 | if (stat & 0x00000010) { |
146 | handle = nouveau_handle_get_class(engctx, class); | 149 | handle = nouveau_handle_get_class(engctx, class); |
147 | if (!handle || nv_call(handle->object, mthd, data)) { | 150 | if (!handle || nv_call(handle->object, mthd, data)) { |
148 | nv_error(priv, "ILLEGAL_MTHD ch %d [0x%010llx] " | 151 | nv_error(priv, |
149 | "subc %d class 0x%04x mthd 0x%04x " | 152 | "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
150 | "data 0x%08x\n", | 153 | chid, inst, nouveau_client_name(engctx), subc, |
151 | chid, inst, subc, class, mthd, data); | 154 | class, mthd, data); |
152 | } | 155 | } |
153 | nouveau_handle_put(handle); | 156 | nouveau_handle_put(handle); |
154 | nv_wr32(priv, 0x400100, 0x00000010); | 157 | nv_wr32(priv, 0x400100, 0x00000010); |
@@ -156,9 +159,10 @@ nve0_graph_intr(struct nouveau_subdev *subdev) | |||
156 | } | 159 | } |
157 | 160 | ||
158 | if (stat & 0x00000020) { | 161 | if (stat & 0x00000020) { |
159 | nv_error(priv, "ILLEGAL_CLASS ch %d [0x%010llx] subc %d " | 162 | nv_error(priv, |
160 | "class 0x%04x mthd 0x%04x data 0x%08x\n", | 163 | "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
161 | chid, inst, subc, class, mthd, data); | 164 | chid, inst, nouveau_client_name(engctx), subc, class, |
165 | mthd, data); | ||
162 | nv_wr32(priv, 0x400100, 0x00000020); | 166 | nv_wr32(priv, 0x400100, 0x00000020); |
163 | stat &= ~0x00000020; | 167 | stat &= ~0x00000020; |
164 | } | 168 | } |
@@ -166,15 +170,15 @@ nve0_graph_intr(struct nouveau_subdev *subdev) | |||
166 | if (stat & 0x00100000) { | 170 | if (stat & 0x00100000) { |
167 | nv_error(priv, "DATA_ERROR ["); | 171 | nv_error(priv, "DATA_ERROR ["); |
168 | nouveau_enum_print(nv50_data_error_names, code); | 172 | nouveau_enum_print(nv50_data_error_names, code); |
169 | printk("] ch %d [0x%010llx] subc %d class 0x%04x " | 173 | pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
170 | "mthd 0x%04x data 0x%08x\n", | 174 | chid, inst, nouveau_client_name(engctx), subc, class, |
171 | chid, inst, subc, class, mthd, data); | 175 | mthd, data); |
172 | nv_wr32(priv, 0x400100, 0x00100000); | 176 | nv_wr32(priv, 0x400100, 0x00100000); |
173 | stat &= ~0x00100000; | 177 | stat &= ~0x00100000; |
174 | } | 178 | } |
175 | 179 | ||
176 | if (stat & 0x00200000) { | 180 | if (stat & 0x00200000) { |
177 | nve0_graph_trap_isr(priv, chid, inst); | 181 | nve0_graph_trap_isr(priv, chid, inst, engctx); |
178 | nv_wr32(priv, 0x400100, 0x00200000); | 182 | nv_wr32(priv, 0x400100, 0x00200000); |
179 | stat &= ~0x00200000; | 183 | stat &= ~0x00200000; |
180 | } | 184 | } |
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c index 9fd86375f4c4..49ecbb859b25 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/client.h> | ||
25 | #include <core/os.h> | 26 | #include <core/os.h> |
26 | #include <core/class.h> | 27 | #include <core/class.h> |
27 | #include <core/engctx.h> | 28 | #include <core/engctx.h> |
@@ -231,8 +232,10 @@ nv31_mpeg_intr(struct nouveau_subdev *subdev) | |||
231 | nv_wr32(priv, 0x00b230, 0x00000001); | 232 | nv_wr32(priv, 0x00b230, 0x00000001); |
232 | 233 | ||
233 | if (show) { | 234 | if (show) { |
234 | nv_error(priv, "ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", | 235 | nv_error(priv, |
235 | chid, inst << 4, stat, type, mthd, data); | 236 | "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n", |
237 | chid, inst << 4, nouveau_client_name(engctx), stat, | ||
238 | type, mthd, data); | ||
236 | } | 239 | } |
237 | 240 | ||
238 | nouveau_engctx_put(engctx); | 241 | nouveau_engctx_put(engctx); |
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c index b0e7e1c01ce6..c48e74953771 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #include <core/namedb.h> | 28 | #include <core/namedb.h> |
29 | #include <core/handle.h> | 29 | #include <core/handle.h> |
30 | #include <core/gpuobj.h> | 30 | #include <core/gpuobj.h> |
31 | #include <core/event.h> | ||
32 | |||
33 | #include <subdev/bar.h> | ||
31 | 34 | ||
32 | #include <engine/software.h> | 35 | #include <engine/software.h> |
33 | #include <engine/disp.h> | 36 | #include <engine/disp.h> |
@@ -90,18 +93,11 @@ nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd, | |||
90 | { | 93 | { |
91 | struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); | 94 | struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); |
92 | struct nouveau_disp *disp = nouveau_disp(object); | 95 | struct nouveau_disp *disp = nouveau_disp(object); |
93 | unsigned long flags; | ||
94 | u32 crtc = *(u32 *)args; | 96 | u32 crtc = *(u32 *)args; |
95 | |||
96 | if (crtc > 1) | 97 | if (crtc > 1) |
97 | return -EINVAL; | 98 | return -EINVAL; |
98 | 99 | ||
99 | disp->vblank.get(disp->vblank.data, crtc); | 100 | nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event); |
100 | |||
101 | spin_lock_irqsave(&disp->vblank.lock, flags); | ||
102 | list_add(&chan->base.vblank.head, &disp->vblank.list); | ||
103 | chan->base.vblank.crtc = crtc; | ||
104 | spin_unlock_irqrestore(&disp->vblank.lock, flags); | ||
105 | return 0; | 101 | return 0; |
106 | } | 102 | } |
107 | 103 | ||
@@ -136,6 +132,29 @@ nv50_software_sclass[] = { | |||
136 | ******************************************************************************/ | 132 | ******************************************************************************/ |
137 | 133 | ||
138 | static int | 134 | static int |
135 | nv50_software_vblsem_release(struct nouveau_eventh *event, int head) | ||
136 | { | ||
137 | struct nouveau_software_chan *chan = | ||
138 | container_of(event, struct nouveau_software_chan, vblank.event); | ||
139 | struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; | ||
140 | struct nouveau_bar *bar = nouveau_bar(priv); | ||
141 | |||
142 | nv_wr32(priv, 0x001704, chan->vblank.channel); | ||
143 | nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); | ||
144 | bar->flush(bar); | ||
145 | |||
146 | if (nv_device(priv)->chipset == 0x50) { | ||
147 | nv_wr32(priv, 0x001570, chan->vblank.offset); | ||
148 | nv_wr32(priv, 0x001574, chan->vblank.value); | ||
149 | } else { | ||
150 | nv_wr32(priv, 0x060010, chan->vblank.offset); | ||
151 | nv_wr32(priv, 0x060014, chan->vblank.value); | ||
152 | } | ||
153 | |||
154 | return NVKM_EVENT_DROP; | ||
155 | } | ||
156 | |||
157 | static int | ||
139 | nv50_software_context_ctor(struct nouveau_object *parent, | 158 | nv50_software_context_ctor(struct nouveau_object *parent, |
140 | struct nouveau_object *engine, | 159 | struct nouveau_object *engine, |
141 | struct nouveau_oclass *oclass, void *data, u32 size, | 160 | struct nouveau_oclass *oclass, void *data, u32 size, |
@@ -150,6 +169,7 @@ nv50_software_context_ctor(struct nouveau_object *parent, | |||
150 | return ret; | 169 | return ret; |
151 | 170 | ||
152 | chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; | 171 | chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; |
172 | chan->base.vblank.event.func = nv50_software_vblsem_release; | ||
153 | return 0; | 173 | return 0; |
154 | } | 174 | } |
155 | 175 | ||
@@ -170,8 +190,8 @@ nv50_software_cclass = { | |||
170 | 190 | ||
171 | static int | 191 | static int |
172 | nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 192 | nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
173 | struct nouveau_oclass *oclass, void *data, u32 size, | 193 | struct nouveau_oclass *oclass, void *data, u32 size, |
174 | struct nouveau_object **pobject) | 194 | struct nouveau_object **pobject) |
175 | { | 195 | { |
176 | struct nv50_software_priv *priv; | 196 | struct nv50_software_priv *priv; |
177 | int ret; | 197 | int ret; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c index 282a1cd1bc2f..a523eaad47e3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c | |||
@@ -25,6 +25,9 @@ | |||
25 | #include <core/os.h> | 25 | #include <core/os.h> |
26 | #include <core/class.h> | 26 | #include <core/class.h> |
27 | #include <core/engctx.h> | 27 | #include <core/engctx.h> |
28 | #include <core/event.h> | ||
29 | |||
30 | #include <subdev/bar.h> | ||
28 | 31 | ||
29 | #include <engine/software.h> | 32 | #include <engine/software.h> |
30 | #include <engine/disp.h> | 33 | #include <engine/disp.h> |
@@ -72,18 +75,12 @@ nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd, | |||
72 | { | 75 | { |
73 | struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); | 76 | struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); |
74 | struct nouveau_disp *disp = nouveau_disp(object); | 77 | struct nouveau_disp *disp = nouveau_disp(object); |
75 | unsigned long flags; | ||
76 | u32 crtc = *(u32 *)args; | 78 | u32 crtc = *(u32 *)args; |
77 | 79 | ||
78 | if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3) | 80 | if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3) |
79 | return -EINVAL; | 81 | return -EINVAL; |
80 | 82 | ||
81 | disp->vblank.get(disp->vblank.data, crtc); | 83 | nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event); |
82 | |||
83 | spin_lock_irqsave(&disp->vblank.lock, flags); | ||
84 | list_add(&chan->base.vblank.head, &disp->vblank.list); | ||
85 | chan->base.vblank.crtc = crtc; | ||
86 | spin_unlock_irqrestore(&disp->vblank.lock, flags); | ||
87 | return 0; | 84 | return 0; |
88 | } | 85 | } |
89 | 86 | ||
@@ -118,6 +115,23 @@ nvc0_software_sclass[] = { | |||
118 | ******************************************************************************/ | 115 | ******************************************************************************/ |
119 | 116 | ||
120 | static int | 117 | static int |
118 | nvc0_software_vblsem_release(struct nouveau_eventh *event, int head) | ||
119 | { | ||
120 | struct nouveau_software_chan *chan = | ||
121 | container_of(event, struct nouveau_software_chan, vblank.event); | ||
122 | struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine; | ||
123 | struct nouveau_bar *bar = nouveau_bar(priv); | ||
124 | |||
125 | nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); | ||
126 | bar->flush(bar); | ||
127 | nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset)); | ||
128 | nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset)); | ||
129 | nv_wr32(priv, 0x060014, chan->vblank.value); | ||
130 | |||
131 | return NVKM_EVENT_DROP; | ||
132 | } | ||
133 | |||
134 | static int | ||
121 | nvc0_software_context_ctor(struct nouveau_object *parent, | 135 | nvc0_software_context_ctor(struct nouveau_object *parent, |
122 | struct nouveau_object *engine, | 136 | struct nouveau_object *engine, |
123 | struct nouveau_oclass *oclass, void *data, u32 size, | 137 | struct nouveau_oclass *oclass, void *data, u32 size, |
@@ -132,6 +146,7 @@ nvc0_software_context_ctor(struct nouveau_object *parent, | |||
132 | return ret; | 146 | return ret; |
133 | 147 | ||
134 | chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; | 148 | chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; |
149 | chan->base.vblank.event.func = nvc0_software_vblsem_release; | ||
135 | return 0; | 150 | return 0; |
136 | } | 151 | } |
137 | 152 | ||
diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index 47c4b3a5bd3a..92d3ab11d962 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h | |||
@@ -154,6 +154,14 @@ struct nve0_channel_ind_class { | |||
154 | u32 engine; | 154 | u32 engine; |
155 | }; | 155 | }; |
156 | 156 | ||
157 | /* 0046: NV04_DISP | ||
158 | */ | ||
159 | |||
160 | #define NV04_DISP_CLASS 0x00000046 | ||
161 | |||
162 | struct nv04_display_class { | ||
163 | }; | ||
164 | |||
157 | /* 5070: NV50_DISP | 165 | /* 5070: NV50_DISP |
158 | * 8270: NV84_DISP | 166 | * 8270: NV84_DISP |
159 | * 8370: NVA0_DISP | 167 | * 8370: NVA0_DISP |
@@ -190,25 +198,6 @@ struct nve0_channel_ind_class { | |||
190 | #define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f | 198 | #define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f |
191 | #define NV50_DISP_SOR_LVDS_SCRIPT 0x00013000 | 199 | #define NV50_DISP_SOR_LVDS_SCRIPT 0x00013000 |
192 | #define NV50_DISP_SOR_LVDS_SCRIPT_ID 0x0000ffff | 200 | #define NV50_DISP_SOR_LVDS_SCRIPT_ID 0x0000ffff |
193 | #define NV94_DISP_SOR_DP_TRAIN 0x00016000 | ||
194 | #define NV94_DISP_SOR_DP_TRAIN_OP 0xf0000000 | ||
195 | #define NV94_DISP_SOR_DP_TRAIN_OP_PATTERN 0x00000000 | ||
196 | #define NV94_DISP_SOR_DP_TRAIN_OP_INIT 0x10000000 | ||
197 | #define NV94_DISP_SOR_DP_TRAIN_OP_FINI 0x20000000 | ||
198 | #define NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD 0x00000001 | ||
199 | #define NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_OFF 0x00000000 | ||
200 | #define NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_ON 0x00000001 | ||
201 | #define NV94_DISP_SOR_DP_TRAIN_PATTERN 0x00000003 | ||
202 | #define NV94_DISP_SOR_DP_TRAIN_PATTERN_DISABLED 0x00000000 | ||
203 | #define NV94_DISP_SOR_DP_LNKCTL 0x00016040 | ||
204 | #define NV94_DISP_SOR_DP_LNKCTL_FRAME 0x80000000 | ||
205 | #define NV94_DISP_SOR_DP_LNKCTL_FRAME_STD 0x00000000 | ||
206 | #define NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH 0x80000000 | ||
207 | #define NV94_DISP_SOR_DP_LNKCTL_WIDTH 0x00001f00 | ||
208 | #define NV94_DISP_SOR_DP_LNKCTL_COUNT 0x00000007 | ||
209 | #define NV94_DISP_SOR_DP_DRVCTL(l) ((l) * 0x40 + 0x00016100) | ||
210 | #define NV94_DISP_SOR_DP_DRVCTL_VS 0x00000300 | ||
211 | #define NV94_DISP_SOR_DP_DRVCTL_PE 0x00000003 | ||
212 | 201 | ||
213 | #define NV50_DISP_DAC_MTHD 0x00020000 | 202 | #define NV50_DISP_DAC_MTHD 0x00020000 |
214 | #define NV50_DISP_DAC_MTHD_TYPE 0x0000f000 | 203 | #define NV50_DISP_DAC_MTHD_TYPE 0x0000f000 |
@@ -230,6 +219,23 @@ struct nve0_channel_ind_class { | |||
230 | #define NV50_DISP_DAC_LOAD 0x0002000c | 219 | #define NV50_DISP_DAC_LOAD 0x0002000c |
231 | #define NV50_DISP_DAC_LOAD_VALUE 0x00000007 | 220 | #define NV50_DISP_DAC_LOAD_VALUE 0x00000007 |
232 | 221 | ||
222 | #define NV50_DISP_PIOR_MTHD 0x00030000 | ||
223 | #define NV50_DISP_PIOR_MTHD_TYPE 0x0000f000 | ||
224 | #define NV50_DISP_PIOR_MTHD_OR 0x00000003 | ||
225 | |||
226 | #define NV50_DISP_PIOR_PWR 0x00030000 | ||
227 | #define NV50_DISP_PIOR_PWR_STATE 0x00000001 | ||
228 | #define NV50_DISP_PIOR_PWR_STATE_ON 0x00000001 | ||
229 | #define NV50_DISP_PIOR_PWR_STATE_OFF 0x00000000 | ||
230 | #define NV50_DISP_PIOR_TMDS_PWR 0x00032000 | ||
231 | #define NV50_DISP_PIOR_TMDS_PWR_STATE 0x00000001 | ||
232 | #define NV50_DISP_PIOR_TMDS_PWR_STATE_ON 0x00000001 | ||
233 | #define NV50_DISP_PIOR_TMDS_PWR_STATE_OFF 0x00000000 | ||
234 | #define NV50_DISP_PIOR_DP_PWR 0x00036000 | ||
235 | #define NV50_DISP_PIOR_DP_PWR_STATE 0x00000001 | ||
236 | #define NV50_DISP_PIOR_DP_PWR_STATE_ON 0x00000001 | ||
237 | #define NV50_DISP_PIOR_DP_PWR_STATE_OFF 0x00000000 | ||
238 | |||
233 | struct nv50_display_class { | 239 | struct nv50_display_class { |
234 | }; | 240 | }; |
235 | 241 | ||
diff --git a/drivers/gpu/drm/nouveau/core/include/core/client.h b/drivers/gpu/drm/nouveau/core/include/core/client.h index 63acc0346ff2..c66eac513803 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/client.h +++ b/drivers/gpu/drm/nouveau/core/include/core/client.h | |||
@@ -7,7 +7,7 @@ struct nouveau_client { | |||
7 | struct nouveau_namedb base; | 7 | struct nouveau_namedb base; |
8 | struct nouveau_handle *root; | 8 | struct nouveau_handle *root; |
9 | struct nouveau_object *device; | 9 | struct nouveau_object *device; |
10 | char name[16]; | 10 | char name[32]; |
11 | u32 debug; | 11 | u32 debug; |
12 | struct nouveau_vm *vm; | 12 | struct nouveau_vm *vm; |
13 | }; | 13 | }; |
@@ -41,5 +41,6 @@ int nouveau_client_create_(const char *name, u64 device, const char *cfg, | |||
41 | 41 | ||
42 | int nouveau_client_init(struct nouveau_client *); | 42 | int nouveau_client_init(struct nouveau_client *); |
43 | int nouveau_client_fini(struct nouveau_client *, bool suspend); | 43 | int nouveau_client_fini(struct nouveau_client *, bool suspend); |
44 | const char *nouveau_client_name(void *obj); | ||
44 | 45 | ||
45 | #endif | 46 | #endif |
diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h index e58b6f0984c1..d351a4e5819c 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/device.h +++ b/drivers/gpu/drm/nouveau/core/include/core/device.h | |||
@@ -26,6 +26,7 @@ enum nv_subdev_type { | |||
26 | */ | 26 | */ |
27 | NVDEV_SUBDEV_MXM, | 27 | NVDEV_SUBDEV_MXM, |
28 | NVDEV_SUBDEV_MC, | 28 | NVDEV_SUBDEV_MC, |
29 | NVDEV_SUBDEV_BUS, | ||
29 | NVDEV_SUBDEV_TIMER, | 30 | NVDEV_SUBDEV_TIMER, |
30 | NVDEV_SUBDEV_FB, | 31 | NVDEV_SUBDEV_FB, |
31 | NVDEV_SUBDEV_LTCG, | 32 | NVDEV_SUBDEV_LTCG, |
diff --git a/drivers/gpu/drm/nouveau/core/include/core/enum.h b/drivers/gpu/drm/nouveau/core/include/core/enum.h index e7b1e181943b..4fc62bb8c1f0 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/enum.h +++ b/drivers/gpu/drm/nouveau/core/include/core/enum.h | |||
@@ -5,12 +5,13 @@ struct nouveau_enum { | |||
5 | u32 value; | 5 | u32 value; |
6 | const char *name; | 6 | const char *name; |
7 | const void *data; | 7 | const void *data; |
8 | u32 data2; | ||
8 | }; | 9 | }; |
9 | 10 | ||
10 | const struct nouveau_enum * | 11 | const struct nouveau_enum * |
11 | nouveau_enum_find(const struct nouveau_enum *, u32 value); | 12 | nouveau_enum_find(const struct nouveau_enum *, u32 value); |
12 | 13 | ||
13 | void | 14 | const struct nouveau_enum * |
14 | nouveau_enum_print(const struct nouveau_enum *en, u32 value); | 15 | nouveau_enum_print(const struct nouveau_enum *en, u32 value); |
15 | 16 | ||
16 | struct nouveau_bitfield { | 17 | struct nouveau_bitfield { |
diff --git a/drivers/gpu/drm/nouveau/core/include/core/event.h b/drivers/gpu/drm/nouveau/core/include/core/event.h new file mode 100644 index 000000000000..9e094408f14e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/event.h | |||
@@ -0,0 +1,36 @@ | |||
1 | #ifndef __NVKM_EVENT_H__ | ||
2 | #define __NVKM_EVENT_H__ | ||
3 | |||
4 | /* return codes from event handlers */ | ||
5 | #define NVKM_EVENT_DROP 0 | ||
6 | #define NVKM_EVENT_KEEP 1 | ||
7 | |||
8 | struct nouveau_eventh { | ||
9 | struct list_head head; | ||
10 | int (*func)(struct nouveau_eventh *, int index); | ||
11 | }; | ||
12 | |||
13 | struct nouveau_event { | ||
14 | spinlock_t lock; | ||
15 | |||
16 | void *priv; | ||
17 | void (*enable)(struct nouveau_event *, int index); | ||
18 | void (*disable)(struct nouveau_event *, int index); | ||
19 | |||
20 | int index_nr; | ||
21 | struct { | ||
22 | struct list_head list; | ||
23 | int refs; | ||
24 | } index[]; | ||
25 | }; | ||
26 | |||
27 | int nouveau_event_create(int index_nr, struct nouveau_event **); | ||
28 | void nouveau_event_destroy(struct nouveau_event **); | ||
29 | void nouveau_event_trigger(struct nouveau_event *, int index); | ||
30 | |||
31 | void nouveau_event_get(struct nouveau_event *, int index, | ||
32 | struct nouveau_eventh *); | ||
33 | void nouveau_event_put(struct nouveau_event *, int index, | ||
34 | struct nouveau_eventh *); | ||
35 | |||
36 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h index 5982935ee23a..6a902672f6f4 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/object.h +++ b/drivers/gpu/drm/nouveau/core/include/core/object.h | |||
@@ -133,7 +133,7 @@ static inline u8 | |||
133 | nv_ro08(void *obj, u64 addr) | 133 | nv_ro08(void *obj, u64 addr) |
134 | { | 134 | { |
135 | u8 data = nv_ofuncs(obj)->rd08(obj, addr); | 135 | u8 data = nv_ofuncs(obj)->rd08(obj, addr); |
136 | nv_spam(obj, "nv_ro08 0x%08x 0x%02x\n", addr, data); | 136 | nv_spam(obj, "nv_ro08 0x%08llx 0x%02x\n", addr, data); |
137 | return data; | 137 | return data; |
138 | } | 138 | } |
139 | 139 | ||
@@ -141,7 +141,7 @@ static inline u16 | |||
141 | nv_ro16(void *obj, u64 addr) | 141 | nv_ro16(void *obj, u64 addr) |
142 | { | 142 | { |
143 | u16 data = nv_ofuncs(obj)->rd16(obj, addr); | 143 | u16 data = nv_ofuncs(obj)->rd16(obj, addr); |
144 | nv_spam(obj, "nv_ro16 0x%08x 0x%04x\n", addr, data); | 144 | nv_spam(obj, "nv_ro16 0x%08llx 0x%04x\n", addr, data); |
145 | return data; | 145 | return data; |
146 | } | 146 | } |
147 | 147 | ||
@@ -149,28 +149,28 @@ static inline u32 | |||
149 | nv_ro32(void *obj, u64 addr) | 149 | nv_ro32(void *obj, u64 addr) |
150 | { | 150 | { |
151 | u32 data = nv_ofuncs(obj)->rd32(obj, addr); | 151 | u32 data = nv_ofuncs(obj)->rd32(obj, addr); |
152 | nv_spam(obj, "nv_ro32 0x%08x 0x%08x\n", addr, data); | 152 | nv_spam(obj, "nv_ro32 0x%08llx 0x%08x\n", addr, data); |
153 | return data; | 153 | return data; |
154 | } | 154 | } |
155 | 155 | ||
156 | static inline void | 156 | static inline void |
157 | nv_wo08(void *obj, u64 addr, u8 data) | 157 | nv_wo08(void *obj, u64 addr, u8 data) |
158 | { | 158 | { |
159 | nv_spam(obj, "nv_wo08 0x%08x 0x%02x\n", addr, data); | 159 | nv_spam(obj, "nv_wo08 0x%08llx 0x%02x\n", addr, data); |
160 | nv_ofuncs(obj)->wr08(obj, addr, data); | 160 | nv_ofuncs(obj)->wr08(obj, addr, data); |
161 | } | 161 | } |
162 | 162 | ||
163 | static inline void | 163 | static inline void |
164 | nv_wo16(void *obj, u64 addr, u16 data) | 164 | nv_wo16(void *obj, u64 addr, u16 data) |
165 | { | 165 | { |
166 | nv_spam(obj, "nv_wo16 0x%08x 0x%04x\n", addr, data); | 166 | nv_spam(obj, "nv_wo16 0x%08llx 0x%04x\n", addr, data); |
167 | nv_ofuncs(obj)->wr16(obj, addr, data); | 167 | nv_ofuncs(obj)->wr16(obj, addr, data); |
168 | } | 168 | } |
169 | 169 | ||
170 | static inline void | 170 | static inline void |
171 | nv_wo32(void *obj, u64 addr, u32 data) | 171 | nv_wo32(void *obj, u64 addr, u32 data) |
172 | { | 172 | { |
173 | nv_spam(obj, "nv_wo32 0x%08x 0x%08x\n", addr, data); | 173 | nv_spam(obj, "nv_wo32 0x%08llx 0x%08x\n", addr, data); |
174 | nv_ofuncs(obj)->wr32(obj, addr, data); | 174 | nv_ofuncs(obj)->wr32(obj, addr, data); |
175 | } | 175 | } |
176 | 176 | ||
diff --git a/drivers/gpu/drm/nouveau/core/include/core/printk.h b/drivers/gpu/drm/nouveau/core/include/core/printk.h index 1d629664f32d..febed2ea5c80 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/printk.h +++ b/drivers/gpu/drm/nouveau/core/include/core/printk.h | |||
@@ -15,7 +15,8 @@ struct nouveau_object; | |||
15 | #define NV_PRINTK_TRACE KERN_DEBUG | 15 | #define NV_PRINTK_TRACE KERN_DEBUG |
16 | #define NV_PRINTK_SPAM KERN_DEBUG | 16 | #define NV_PRINTK_SPAM KERN_DEBUG |
17 | 17 | ||
18 | void nv_printk_(struct nouveau_object *, const char *, int, const char *, ...); | 18 | void __printf(4, 5) |
19 | nv_printk_(struct nouveau_object *, const char *, int, const char *, ...); | ||
19 | 20 | ||
20 | #define nv_printk(o,l,f,a...) do { \ | 21 | #define nv_printk(o,l,f,a...) do { \ |
21 | if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG) \ | 22 | if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG) \ |
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h index 46948285f3e7..28da6772c095 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/disp.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/disp.h | |||
@@ -4,18 +4,11 @@ | |||
4 | #include <core/object.h> | 4 | #include <core/object.h> |
5 | #include <core/engine.h> | 5 | #include <core/engine.h> |
6 | #include <core/device.h> | 6 | #include <core/device.h> |
7 | #include <core/event.h> | ||
7 | 8 | ||
8 | struct nouveau_disp { | 9 | struct nouveau_disp { |
9 | struct nouveau_engine base; | 10 | struct nouveau_engine base; |
10 | 11 | struct nouveau_event *vblank; | |
11 | struct { | ||
12 | struct list_head list; | ||
13 | spinlock_t lock; | ||
14 | void (*notify)(void *, int); | ||
15 | void (*get)(void *, int); | ||
16 | void (*put)(void *, int); | ||
17 | void *data; | ||
18 | } vblank; | ||
19 | }; | 12 | }; |
20 | 13 | ||
21 | static inline struct nouveau_disp * | 14 | static inline struct nouveau_disp * |
@@ -24,16 +17,22 @@ nouveau_disp(void *obj) | |||
24 | return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP]; | 17 | return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP]; |
25 | } | 18 | } |
26 | 19 | ||
27 | #define nouveau_disp_create(p,e,c,i,x,d) \ | 20 | #define nouveau_disp_create(p,e,c,h,i,x,d) \ |
28 | nouveau_engine_create((p), (e), (c), true, (i), (x), (d)) | 21 | nouveau_disp_create_((p), (e), (c), (h), (i), (x), \ |
29 | #define nouveau_disp_destroy(d) \ | 22 | sizeof(**d), (void **)d) |
30 | nouveau_engine_destroy(&(d)->base) | 23 | #define nouveau_disp_destroy(d) ({ \ |
24 | struct nouveau_disp *disp = (d); \ | ||
25 | _nouveau_disp_dtor(nv_object(disp)); \ | ||
26 | }) | ||
31 | #define nouveau_disp_init(d) \ | 27 | #define nouveau_disp_init(d) \ |
32 | nouveau_engine_init(&(d)->base) | 28 | nouveau_engine_init(&(d)->base) |
33 | #define nouveau_disp_fini(d,s) \ | 29 | #define nouveau_disp_fini(d,s) \ |
34 | nouveau_engine_fini(&(d)->base, (s)) | 30 | nouveau_engine_fini(&(d)->base, (s)) |
35 | 31 | ||
36 | #define _nouveau_disp_dtor _nouveau_engine_dtor | 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 *); | ||
37 | #define _nouveau_disp_init _nouveau_engine_init | 36 | #define _nouveau_disp_init _nouveau_engine_init |
38 | #define _nouveau_disp_fini _nouveau_engine_fini | 37 | #define _nouveau_disp_fini _nouveau_engine_fini |
39 | 38 | ||
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h index f18846c8c6fe..b46c197709f3 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h | |||
@@ -65,6 +65,8 @@ struct nouveau_fifo_base { | |||
65 | struct nouveau_fifo { | 65 | struct nouveau_fifo { |
66 | struct nouveau_engine base; | 66 | struct nouveau_engine base; |
67 | 67 | ||
68 | struct nouveau_event *uevent; | ||
69 | |||
68 | struct nouveau_object **channel; | 70 | struct nouveau_object **channel; |
69 | spinlock_t lock; | 71 | spinlock_t lock; |
70 | u16 min; | 72 | u16 min; |
@@ -92,6 +94,8 @@ int nouveau_fifo_create_(struct nouveau_object *, struct nouveau_object *, | |||
92 | struct nouveau_oclass *, int min, int max, | 94 | struct nouveau_oclass *, int min, int max, |
93 | int size, void **); | 95 | int size, void **); |
94 | void nouveau_fifo_destroy(struct nouveau_fifo *); | 96 | void nouveau_fifo_destroy(struct nouveau_fifo *); |
97 | const char * | ||
98 | nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid); | ||
95 | 99 | ||
96 | #define _nouveau_fifo_init _nouveau_engine_init | 100 | #define _nouveau_fifo_init _nouveau_engine_init |
97 | #define _nouveau_fifo_fini _nouveau_engine_fini | 101 | #define _nouveau_fifo_fini _nouveau_engine_fini |
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/software.h b/drivers/gpu/drm/nouveau/core/include/engine/software.h index c945691c8564..45799487e573 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/software.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/software.h | |||
@@ -3,17 +3,17 @@ | |||
3 | 3 | ||
4 | #include <core/engine.h> | 4 | #include <core/engine.h> |
5 | #include <core/engctx.h> | 5 | #include <core/engctx.h> |
6 | #include <core/event.h> | ||
6 | 7 | ||
7 | struct nouveau_software_chan { | 8 | struct nouveau_software_chan { |
8 | struct nouveau_engctx base; | 9 | struct nouveau_engctx base; |
9 | 10 | ||
10 | struct { | 11 | struct { |
11 | struct list_head head; | 12 | struct nouveau_eventh event; |
12 | u32 channel; | 13 | u32 channel; |
13 | u32 ctxdma; | 14 | u32 ctxdma; |
14 | u64 offset; | 15 | u64 offset; |
15 | u32 value; | 16 | u32 value; |
16 | u32 crtc; | ||
17 | } vblank; | 17 | } vblank; |
18 | 18 | ||
19 | int (*flip)(void *); | 19 | int (*flip)(void *); |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h index b79025da581e..123270e9813a 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h | |||
@@ -16,6 +16,8 @@ enum dcb_output_type { | |||
16 | 16 | ||
17 | struct dcb_output { | 17 | struct dcb_output { |
18 | int index; /* may not be raw dcb index if merging has happened */ | 18 | int index; /* may not be raw dcb index if merging has happened */ |
19 | u16 hasht; | ||
20 | u16 hashm; | ||
19 | enum dcb_output_type type; | 21 | enum dcb_output_type type; |
20 | uint8_t i2c_index; | 22 | uint8_t i2c_index; |
21 | uint8_t heads; | 23 | uint8_t heads; |
@@ -25,6 +27,7 @@ struct dcb_output { | |||
25 | uint8_t or; | 27 | uint8_t or; |
26 | uint8_t link; | 28 | uint8_t link; |
27 | bool duallink_possible; | 29 | bool duallink_possible; |
30 | uint8_t extdev; | ||
28 | union { | 31 | union { |
29 | struct sor_conf { | 32 | struct sor_conf { |
30 | int link; | 33 | int link; |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h index e6563b5cb08e..96d3364f6db3 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h | |||
@@ -1,17 +1,22 @@ | |||
1 | #ifndef __NVBIOS_GPIO_H__ | 1 | #ifndef __NVBIOS_GPIO_H__ |
2 | #define __NVBIOS_GPIO_H__ | 2 | #define __NVBIOS_GPIO_H__ |
3 | 3 | ||
4 | struct nouveau_bios; | ||
5 | |||
6 | enum dcb_gpio_func_name { | 4 | enum dcb_gpio_func_name { |
7 | DCB_GPIO_PANEL_POWER = 0x01, | 5 | DCB_GPIO_PANEL_POWER = 0x01, |
8 | DCB_GPIO_TVDAC0 = 0x0c, | 6 | DCB_GPIO_TVDAC0 = 0x0c, |
9 | DCB_GPIO_TVDAC1 = 0x2d, | 7 | DCB_GPIO_TVDAC1 = 0x2d, |
10 | DCB_GPIO_PWM_FAN = 0x09, | 8 | DCB_GPIO_FAN = 0x09, |
11 | DCB_GPIO_FAN_SENSE = 0x3d, | 9 | DCB_GPIO_FAN_SENSE = 0x3d, |
12 | DCB_GPIO_UNUSED = 0xff | 10 | DCB_GPIO_UNUSED = 0xff |
13 | }; | 11 | }; |
14 | 12 | ||
13 | #define DCB_GPIO_LOG_DIR 0x02 | ||
14 | #define DCB_GPIO_LOG_DIR_OUT 0x00 | ||
15 | #define DCB_GPIO_LOG_DIR_IN 0x02 | ||
16 | #define DCB_GPIO_LOG_VAL 0x01 | ||
17 | #define DCB_GPIO_LOG_VAL_LO 0x00 | ||
18 | #define DCB_GPIO_LOG_VAL_HI 0x01 | ||
19 | |||
15 | struct dcb_gpio_func { | 20 | struct dcb_gpio_func { |
16 | u8 func; | 21 | u8 func; |
17 | u8 line; | 22 | u8 line; |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h index 5079bedfd985..10b57a19a7de 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h | |||
@@ -15,7 +15,7 @@ struct dcb_i2c_entry { | |||
15 | enum dcb_i2c_type type; | 15 | enum dcb_i2c_type type; |
16 | u8 drive; | 16 | u8 drive; |
17 | u8 sense; | 17 | u8 sense; |
18 | u32 data; | 18 | u8 share; |
19 | }; | 19 | }; |
20 | 20 | ||
21 | u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); | 21 | u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h index a2c4296fc5f6..083541dbe9c8 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h | |||
@@ -23,11 +23,27 @@ struct nvbios_therm_sensor { | |||
23 | struct nvbios_therm_threshold thrs_shutdown; | 23 | struct nvbios_therm_threshold thrs_shutdown; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | /* no vbios have more than 6 */ | ||
27 | #define NOUVEAU_TEMP_FAN_TRIP_MAX 10 | ||
28 | struct nouveau_therm_trip_point { | ||
29 | int fan_duty; | ||
30 | int temp; | ||
31 | int hysteresis; | ||
32 | }; | ||
33 | |||
26 | struct nvbios_therm_fan { | 34 | struct nvbios_therm_fan { |
27 | u16 pwm_freq; | 35 | u16 pwm_freq; |
28 | 36 | ||
29 | u8 min_duty; | 37 | u8 min_duty; |
30 | u8 max_duty; | 38 | u8 max_duty; |
39 | |||
40 | u16 bump_period; | ||
41 | u16 slow_down_period; | ||
42 | |||
43 | struct nouveau_therm_trip_point trip[NOUVEAU_TEMP_FAN_TRIP_MAX]; | ||
44 | u8 nr_fan_trip; | ||
45 | u8 linear_min_temp; | ||
46 | u8 linear_max_temp; | ||
31 | }; | 47 | }; |
32 | 48 | ||
33 | enum nvbios_therm_domain { | 49 | enum nvbios_therm_domain { |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h new file mode 100644 index 000000000000..360baab52e4c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef __NVBIOS_XPIO_H__ | ||
2 | #define __NVBIOS_XPIO_H__ | ||
3 | |||
4 | #define NVBIOS_XPIO_FLAG_AUX 0x10 | ||
5 | #define NVBIOS_XPIO_FLAG_AUX0 0x00 | ||
6 | #define NVBIOS_XPIO_FLAG_AUX1 0x10 | ||
7 | |||
8 | struct nvbios_xpio { | ||
9 | u8 type; | ||
10 | u8 addr; | ||
11 | u8 flags; | ||
12 | }; | ||
13 | |||
14 | u16 dcb_xpio_table(struct nouveau_bios *, u8 idx, | ||
15 | u8 *ver, u8 *hdr, u8 *cnt, u8 *len); | ||
16 | u16 dcb_xpio_parse(struct nouveau_bios *, u8 idx, | ||
17 | u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_xpio *); | ||
18 | |||
19 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bus.h b/drivers/gpu/drm/nouveau/core/include/subdev/bus.h new file mode 100644 index 000000000000..7d88ec4a6d06 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bus.h | |||
@@ -0,0 +1,41 @@ | |||
1 | #ifndef __NOUVEAU_BUS_H__ | ||
2 | #define __NOUVEAU_BUS_H__ | ||
3 | |||
4 | #include <core/subdev.h> | ||
5 | #include <core/device.h> | ||
6 | |||
7 | struct nouveau_bus_intr { | ||
8 | u32 stat; | ||
9 | u32 unit; | ||
10 | }; | ||
11 | |||
12 | struct nouveau_bus { | ||
13 | struct nouveau_subdev base; | ||
14 | }; | ||
15 | |||
16 | static inline struct nouveau_bus * | ||
17 | nouveau_bus(void *obj) | ||
18 | { | ||
19 | return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_BUS]; | ||
20 | } | ||
21 | |||
22 | #define nouveau_bus_create(p, e, o, d) \ | ||
23 | nouveau_subdev_create_((p), (e), (o), 0, "PBUS", "master", \ | ||
24 | sizeof(**d), (void **)d) | ||
25 | #define nouveau_bus_destroy(p) \ | ||
26 | nouveau_subdev_destroy(&(p)->base) | ||
27 | #define nouveau_bus_init(p) \ | ||
28 | nouveau_subdev_init(&(p)->base) | ||
29 | #define nouveau_bus_fini(p, s) \ | ||
30 | nouveau_subdev_fini(&(p)->base, (s)) | ||
31 | |||
32 | #define _nouveau_bus_dtor _nouveau_subdev_dtor | ||
33 | #define _nouveau_bus_init _nouveau_subdev_init | ||
34 | #define _nouveau_bus_fini _nouveau_subdev_fini | ||
35 | |||
36 | extern struct nouveau_oclass nv04_bus_oclass; | ||
37 | extern struct nouveau_oclass nv31_bus_oclass; | ||
38 | extern struct nouveau_oclass nv50_bus_oclass; | ||
39 | extern struct nouveau_oclass nvc0_bus_oclass; | ||
40 | |||
41 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h index b75e8f18e52c..c85b9f1579ad 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <core/subdev.h> | 4 | #include <core/subdev.h> |
5 | #include <core/device.h> | 5 | #include <core/device.h> |
6 | #include <core/event.h> | ||
6 | 7 | ||
7 | #include <subdev/bios.h> | 8 | #include <subdev/bios.h> |
8 | #include <subdev/bios/gpio.h> | 9 | #include <subdev/bios/gpio.h> |
@@ -10,28 +11,18 @@ | |||
10 | struct nouveau_gpio { | 11 | struct nouveau_gpio { |
11 | struct nouveau_subdev base; | 12 | struct nouveau_subdev base; |
12 | 13 | ||
14 | struct nouveau_event *events; | ||
15 | |||
13 | /* hardware interfaces */ | 16 | /* hardware interfaces */ |
14 | void (*reset)(struct nouveau_gpio *, u8 func); | 17 | void (*reset)(struct nouveau_gpio *, u8 func); |
15 | int (*drive)(struct nouveau_gpio *, int line, int dir, int out); | 18 | int (*drive)(struct nouveau_gpio *, int line, int dir, int out); |
16 | int (*sense)(struct nouveau_gpio *, int line); | 19 | int (*sense)(struct nouveau_gpio *, int line); |
17 | void (*irq_enable)(struct nouveau_gpio *, int line, bool); | ||
18 | 20 | ||
19 | /* software interfaces */ | 21 | /* software interfaces */ |
20 | int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line, | 22 | int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line, |
21 | struct dcb_gpio_func *); | 23 | struct dcb_gpio_func *); |
22 | int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state); | 24 | int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state); |
23 | int (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line); | 25 | int (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line); |
24 | int (*irq)(struct nouveau_gpio *, int idx, u8 tag, u8 line, bool on); | ||
25 | |||
26 | /* interrupt handling */ | ||
27 | struct list_head isr; | ||
28 | spinlock_t lock; | ||
29 | |||
30 | void (*isr_run)(struct nouveau_gpio *, int idx, u32 mask); | ||
31 | int (*isr_add)(struct nouveau_gpio *, int idx, u8 tag, u8 line, | ||
32 | void (*)(void *, int state), void *data); | ||
33 | void (*isr_del)(struct nouveau_gpio *, int idx, u8 tag, u8 line, | ||
34 | void (*)(void *, int state), void *data); | ||
35 | }; | 26 | }; |
36 | 27 | ||
37 | static inline struct nouveau_gpio * | 28 | static inline struct nouveau_gpio * |
@@ -40,25 +31,23 @@ nouveau_gpio(void *obj) | |||
40 | return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO]; | 31 | return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO]; |
41 | } | 32 | } |
42 | 33 | ||
43 | #define nouveau_gpio_create(p,e,o,d) \ | 34 | #define nouveau_gpio_create(p,e,o,l,d) \ |
44 | nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d) | 35 | nouveau_gpio_create_((p), (e), (o), (l), sizeof(**d), (void **)d) |
45 | #define nouveau_gpio_destroy(p) \ | 36 | #define nouveau_gpio_destroy(p) ({ \ |
46 | nouveau_subdev_destroy(&(p)->base) | 37 | struct nouveau_gpio *gpio = (p); \ |
38 | _nouveau_gpio_dtor(nv_object(gpio)); \ | ||
39 | }) | ||
47 | #define nouveau_gpio_fini(p,s) \ | 40 | #define nouveau_gpio_fini(p,s) \ |
48 | nouveau_subdev_fini(&(p)->base, (s)) | 41 | nouveau_subdev_fini(&(p)->base, (s)) |
49 | 42 | ||
50 | int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, | 43 | int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, |
51 | struct nouveau_oclass *, int, void **); | 44 | struct nouveau_oclass *, int, int, void **); |
52 | int nouveau_gpio_init(struct nouveau_gpio *); | 45 | void _nouveau_gpio_dtor(struct nouveau_object *); |
46 | int nouveau_gpio_init(struct nouveau_gpio *); | ||
53 | 47 | ||
54 | extern struct nouveau_oclass nv10_gpio_oclass; | 48 | extern struct nouveau_oclass nv10_gpio_oclass; |
55 | extern struct nouveau_oclass nv50_gpio_oclass; | 49 | extern struct nouveau_oclass nv50_gpio_oclass; |
56 | extern struct nouveau_oclass nvd0_gpio_oclass; | 50 | extern struct nouveau_oclass nvd0_gpio_oclass; |
57 | 51 | extern struct nouveau_oclass nve0_gpio_oclass; | |
58 | void nv50_gpio_dtor(struct nouveau_object *); | ||
59 | int nv50_gpio_init(struct nouveau_object *); | ||
60 | int nv50_gpio_fini(struct nouveau_object *, bool); | ||
61 | void nv50_gpio_intr(struct nouveau_subdev *); | ||
62 | void nv50_gpio_irq_enable(struct nouveau_gpio *, int line, bool); | ||
63 | 52 | ||
64 | #endif | 53 | #endif |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h index b93ab01e3785..888384c0bed8 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h | |||
@@ -10,23 +10,59 @@ | |||
10 | #define NV_I2C_PORT(n) (0x00 + (n)) | 10 | #define NV_I2C_PORT(n) (0x00 + (n)) |
11 | #define NV_I2C_DEFAULT(n) (0x80 + (n)) | 11 | #define NV_I2C_DEFAULT(n) (0x80 + (n)) |
12 | 12 | ||
13 | #define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n)) | ||
14 | #define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8) | ||
15 | #define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8) | ||
16 | |||
13 | struct nouveau_i2c_port { | 17 | struct nouveau_i2c_port { |
18 | struct nouveau_object base; | ||
14 | struct i2c_adapter adapter; | 19 | struct i2c_adapter adapter; |
15 | struct nouveau_i2c *i2c; | 20 | |
16 | struct i2c_algo_bit_data bit; | ||
17 | struct list_head head; | 21 | struct list_head head; |
18 | u8 index; | 22 | u8 index; |
19 | u8 type; | 23 | |
20 | u32 dcb; | 24 | const struct nouveau_i2c_func *func; |
21 | u32 drive; | 25 | }; |
22 | u32 sense; | 26 | |
23 | u32 state; | 27 | 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); | ||
32 | void (*drive_sda)(struct nouveau_i2c_port *, int); | ||
33 | int (*sense_scl)(struct nouveau_i2c_port *); | ||
34 | int (*sense_sda)(struct nouveau_i2c_port *); | ||
35 | |||
36 | int (*aux)(struct nouveau_i2c_port *, u8, u32, u8 *, u8); | ||
37 | int (*pattern)(struct nouveau_i2c_port *, int pattern); | ||
38 | 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); | ||
24 | }; | 40 | }; |
25 | 41 | ||
42 | #define nouveau_i2c_port_create(p,e,o,i,a,d) \ | ||
43 | nouveau_i2c_port_create_((p), (e), (o), (i), (a), \ | ||
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 *, int, void **); | ||
57 | void _nouveau_i2c_port_dtor(struct nouveau_object *); | ||
58 | #define _nouveau_i2c_port_init nouveau_object_init | ||
59 | #define _nouveau_i2c_port_fini nouveau_object_fini | ||
60 | |||
26 | struct nouveau_i2c { | 61 | struct nouveau_i2c { |
27 | struct nouveau_subdev base; | 62 | struct nouveau_subdev base; |
28 | 63 | ||
29 | struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); | 64 | struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); |
65 | struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); | ||
30 | int (*identify)(struct nouveau_i2c *, int index, | 66 | int (*identify)(struct nouveau_i2c *, int index, |
31 | const char *what, struct i2c_board_info *, | 67 | const char *what, struct i2c_board_info *, |
32 | bool (*match)(struct nouveau_i2c_port *, | 68 | bool (*match)(struct nouveau_i2c_port *, |
@@ -40,21 +76,76 @@ nouveau_i2c(void *obj) | |||
40 | return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C]; | 76 | return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C]; |
41 | } | 77 | } |
42 | 78 | ||
43 | extern struct nouveau_oclass nouveau_i2c_oclass; | 79 | #define nouveau_i2c_create(p,e,o,s,d) \ |
80 | nouveau_i2c_create_((p), (e), (o), (s), sizeof(**d), (void **)d) | ||
81 | #define nouveau_i2c_destroy(p) ({ \ | ||
82 | struct nouveau_i2c *i2c = (p); \ | ||
83 | _nouveau_i2c_dtor(nv_object(i2c)); \ | ||
84 | }) | ||
85 | #define nouveau_i2c_init(p) ({ \ | ||
86 | struct nouveau_i2c *i2c = (p); \ | ||
87 | _nouveau_i2c_init(nv_object(i2c)); \ | ||
88 | }) | ||
89 | #define nouveau_i2c_fini(p,s) ({ \ | ||
90 | struct nouveau_i2c *i2c = (p); \ | ||
91 | _nouveau_i2c_fini(nv_object(i2c), (s)); \ | ||
92 | }) | ||
44 | 93 | ||
45 | void nouveau_i2c_drive_scl(void *, int); | 94 | int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *, |
46 | void nouveau_i2c_drive_sda(void *, int); | 95 | struct nouveau_oclass *, struct nouveau_oclass *, |
47 | int nouveau_i2c_sense_scl(void *); | 96 | int, void **); |
48 | int nouveau_i2c_sense_sda(void *); | 97 | void _nouveau_i2c_dtor(struct nouveau_object *); |
98 | int _nouveau_i2c_init(struct nouveau_object *); | ||
99 | int _nouveau_i2c_fini(struct nouveau_object *, bool); | ||
49 | 100 | ||
50 | int nv_rdi2cr(struct nouveau_i2c_port *, u8 addr, u8 reg); | 101 | extern struct nouveau_oclass nv04_i2c_oclass; |
51 | int nv_wri2cr(struct nouveau_i2c_port *, u8 addr, u8 reg, u8 val); | 102 | extern struct nouveau_oclass nv4e_i2c_oclass; |
52 | bool nv_probe_i2c(struct nouveau_i2c_port *, u8 addr); | 103 | extern struct nouveau_oclass nv50_i2c_oclass; |
53 | 104 | extern struct nouveau_oclass nv94_i2c_oclass; | |
54 | int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size); | 105 | extern struct nouveau_oclass nvd0_i2c_oclass; |
55 | int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size); | 106 | extern struct nouveau_oclass nouveau_anx9805_sclass[]; |
56 | 107 | ||
57 | extern const struct i2c_algorithm nouveau_i2c_bit_algo; | 108 | extern const struct i2c_algorithm nouveau_i2c_bit_algo; |
58 | extern const struct i2c_algorithm nouveau_i2c_aux_algo; | 109 | extern const struct i2c_algorithm nouveau_i2c_aux_algo; |
59 | 110 | ||
111 | static inline int | ||
112 | nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg) | ||
113 | { | ||
114 | u8 val; | ||
115 | struct i2c_msg msgs[] = { | ||
116 | { .addr = addr, .flags = 0, .len = 1, .buf = ® }, | ||
117 | { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val }, | ||
118 | }; | ||
119 | |||
120 | int ret = i2c_transfer(&port->adapter, msgs, 2); | ||
121 | if (ret != 2) | ||
122 | return -EIO; | ||
123 | |||
124 | return val; | ||
125 | } | ||
126 | |||
127 | static inline int | ||
128 | nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val) | ||
129 | { | ||
130 | u8 buf[2] = { reg, val }; | ||
131 | struct i2c_msg msgs[] = { | ||
132 | { .addr = addr, .flags = 0, .len = 2, .buf = buf }, | ||
133 | }; | ||
134 | |||
135 | int ret = i2c_transfer(&port->adapter, msgs, 1); | ||
136 | if (ret != 1) | ||
137 | return -EIO; | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static inline bool | ||
143 | nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr) | ||
144 | { | ||
145 | return nv_rdi2cr(port, addr, 0) >= 0; | ||
146 | } | ||
147 | |||
148 | int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size); | ||
149 | int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size); | ||
150 | |||
60 | #endif | 151 | #endif |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h index faee569fd458..6b17b614629f 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h | |||
@@ -4,10 +4,10 @@ | |||
4 | #include <core/device.h> | 4 | #include <core/device.h> |
5 | #include <core/subdev.h> | 5 | #include <core/subdev.h> |
6 | 6 | ||
7 | enum nouveau_therm_fan_mode { | 7 | enum nouveau_therm_mode { |
8 | FAN_CONTROL_NONE = 0, | 8 | NOUVEAU_THERM_CTRL_NONE = 0, |
9 | FAN_CONTROL_MANUAL = 1, | 9 | NOUVEAU_THERM_CTRL_MANUAL = 1, |
10 | FAN_CONTROL_NR, | 10 | NOUVEAU_THERM_CTRL_AUTO = 2, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | enum nouveau_therm_attr_type { | 13 | enum nouveau_therm_attr_type { |
@@ -28,6 +28,11 @@ enum nouveau_therm_attr_type { | |||
28 | struct nouveau_therm { | 28 | struct nouveau_therm { |
29 | struct nouveau_subdev base; | 29 | struct nouveau_subdev base; |
30 | 30 | ||
31 | int (*pwm_ctrl)(struct nouveau_therm *, int line, bool); | ||
32 | int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *); | ||
33 | int (*pwm_set)(struct nouveau_therm *, int line, u32, u32); | ||
34 | int (*pwm_clock)(struct nouveau_therm *); | ||
35 | |||
31 | int (*fan_get)(struct nouveau_therm *); | 36 | int (*fan_get)(struct nouveau_therm *); |
32 | int (*fan_set)(struct nouveau_therm *, int); | 37 | int (*fan_set)(struct nouveau_therm *, int); |
33 | int (*fan_sense)(struct nouveau_therm *); | 38 | int (*fan_sense)(struct nouveau_therm *); |
@@ -46,13 +51,29 @@ nouveau_therm(void *obj) | |||
46 | } | 51 | } |
47 | 52 | ||
48 | #define nouveau_therm_create(p,e,o,d) \ | 53 | #define nouveau_therm_create(p,e,o,d) \ |
49 | nouveau_subdev_create((p), (e), (o), 0, "THERM", "therm", d) | 54 | nouveau_therm_create_((p), (e), (o), sizeof(**d), (void **)d) |
50 | #define nouveau_therm_destroy(p) \ | 55 | #define nouveau_therm_destroy(p) ({ \ |
51 | nouveau_subdev_destroy(&(p)->base) | 56 | struct nouveau_therm *therm = (p); \ |
57 | _nouveau_therm_dtor(nv_object(therm)); \ | ||
58 | }) | ||
59 | #define nouveau_therm_init(p) ({ \ | ||
60 | struct nouveau_therm *therm = (p); \ | ||
61 | _nouveau_therm_init(nv_object(therm)); \ | ||
62 | }) | ||
63 | #define nouveau_therm_fini(p,s) ({ \ | ||
64 | struct nouveau_therm *therm = (p); \ | ||
65 | _nouveau_therm_init(nv_object(therm), (s)); \ | ||
66 | }) | ||
52 | 67 | ||
53 | #define _nouveau_therm_dtor _nouveau_subdev_dtor | 68 | int nouveau_therm_create_(struct nouveau_object *, struct nouveau_object *, |
69 | struct nouveau_oclass *, int, void **); | ||
70 | void _nouveau_therm_dtor(struct nouveau_object *); | ||
71 | int _nouveau_therm_init(struct nouveau_object *); | ||
72 | int _nouveau_therm_fini(struct nouveau_object *, bool); | ||
54 | 73 | ||
55 | extern struct nouveau_oclass nv40_therm_oclass; | 74 | extern struct nouveau_oclass nv40_therm_oclass; |
56 | extern struct nouveau_oclass nv50_therm_oclass; | 75 | extern struct nouveau_oclass nv50_therm_oclass; |
76 | extern struct nouveau_oclass nva3_therm_oclass; | ||
77 | extern struct nouveau_oclass nvd0_therm_oclass; | ||
57 | 78 | ||
58 | #endif | 79 | #endif |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h index c24ec8ab3db4..e465d158d352 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h | |||
@@ -10,6 +10,14 @@ struct nouveau_alarm { | |||
10 | void (*func)(struct nouveau_alarm *); | 10 | void (*func)(struct nouveau_alarm *); |
11 | }; | 11 | }; |
12 | 12 | ||
13 | static inline void | ||
14 | nouveau_alarm_init(struct nouveau_alarm *alarm, | ||
15 | void (*func)(struct nouveau_alarm *)) | ||
16 | { | ||
17 | INIT_LIST_HEAD(&alarm->head); | ||
18 | alarm->func = func; | ||
19 | } | ||
20 | |||
13 | bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data); | 21 | bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data); |
14 | bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data); | 22 | bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data); |
15 | bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data); | 23 | bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data); |
diff --git a/drivers/gpu/drm/nouveau/core/os.h b/drivers/gpu/drm/nouveau/core/os.h index cfe3b9cad156..eb496033b55c 100644 --- a/drivers/gpu/drm/nouveau/core/os.h +++ b/drivers/gpu/drm/nouveau/core/os.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/vmalloc.h> | 16 | #include <linux/vmalloc.h> |
17 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
18 | #include <linux/dmi.h> | 18 | #include <linux/dmi.h> |
19 | #include <linux/reboot.h> | ||
19 | 20 | ||
20 | #include <asm/unaligned.h> | 21 | #include <asm/unaligned.h> |
21 | 22 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index f621f69fa1a2..e816f06637a7 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c | |||
@@ -172,7 +172,7 @@ out: | |||
172 | nv_wr32(bios, pcireg, access); | 172 | nv_wr32(bios, pcireg, access); |
173 | } | 173 | } |
174 | 174 | ||
175 | #if defined(CONFIG_ACPI) | 175 | #if defined(CONFIG_ACPI) && defined(CONFIG_X86) |
176 | int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); | 176 | int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); |
177 | bool nouveau_acpi_rom_supported(struct pci_dev *pdev); | 177 | bool nouveau_acpi_rom_supported(struct pci_dev *pdev); |
178 | #else | 178 | #else |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c index 0fd87df99dd6..2d9b9d7a7992 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c | |||
@@ -107,6 +107,18 @@ dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) | |||
107 | return 0x0000; | 107 | return 0x0000; |
108 | } | 108 | } |
109 | 109 | ||
110 | static inline u16 | ||
111 | dcb_outp_hasht(struct dcb_output *outp) | ||
112 | { | ||
113 | return (outp->extdev << 8) | (outp->location << 4) | outp->type; | ||
114 | } | ||
115 | |||
116 | static inline u16 | ||
117 | dcb_outp_hashm(struct dcb_output *outp) | ||
118 | { | ||
119 | return (outp->heads << 8) | (outp->link << 6) | outp->or; | ||
120 | } | ||
121 | |||
110 | u16 | 122 | u16 |
111 | dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, | 123 | dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, |
112 | struct dcb_output *outp) | 124 | struct dcb_output *outp) |
@@ -135,34 +147,28 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, | |||
135 | case DCB_OUTPUT_DP: | 147 | case DCB_OUTPUT_DP: |
136 | outp->link = (conf & 0x00000030) >> 4; | 148 | outp->link = (conf & 0x00000030) >> 4; |
137 | outp->sorconf.link = outp->link; /*XXX*/ | 149 | outp->sorconf.link = outp->link; /*XXX*/ |
150 | outp->extdev = 0x00; | ||
151 | if (outp->location != 0) | ||
152 | outp->extdev = (conf & 0x0000ff00) >> 8; | ||
138 | break; | 153 | break; |
139 | default: | 154 | default: |
140 | break; | 155 | break; |
141 | } | 156 | } |
142 | } | 157 | } |
158 | |||
159 | outp->hasht = dcb_outp_hasht(outp); | ||
160 | outp->hashm = dcb_outp_hashm(outp); | ||
143 | } | 161 | } |
144 | return dcb; | 162 | return dcb; |
145 | } | 163 | } |
146 | 164 | ||
147 | static inline u16 | ||
148 | dcb_outp_hasht(struct dcb_output *outp) | ||
149 | { | ||
150 | return outp->type; | ||
151 | } | ||
152 | |||
153 | static inline u16 | ||
154 | dcb_outp_hashm(struct dcb_output *outp) | ||
155 | { | ||
156 | return (outp->heads << 8) | (outp->link << 6) | outp->or; | ||
157 | } | ||
158 | |||
159 | u16 | 165 | u16 |
160 | dcb_outp_match(struct nouveau_bios *bios, u16 type, u16 mask, | 166 | dcb_outp_match(struct nouveau_bios *bios, u16 type, u16 mask, |
161 | u8 *ver, u8 *len, struct dcb_output *outp) | 167 | u8 *ver, u8 *len, struct dcb_output *outp) |
162 | { | 168 | { |
163 | u16 dcb, idx = 0; | 169 | u16 dcb, idx = 0; |
164 | while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) { | 170 | while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) { |
165 | if (dcb_outp_hasht(outp) == type) { | 171 | if ((dcb_outp_hasht(outp) & 0x00ff) == (type & 0x00ff)) { |
166 | if ((dcb_outp_hashm(outp) & mask) == mask) | 172 | if ((dcb_outp_hashm(outp) & mask) == mask) |
167 | break; | 173 | break; |
168 | } | 174 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c b/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c index 5afb568b2d69..b2a676e53580 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c | |||
@@ -48,7 +48,7 @@ extdev_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) | |||
48 | return extdev + *hdr; | 48 | return extdev + *hdr; |
49 | } | 49 | } |
50 | 50 | ||
51 | u16 | 51 | static u16 |
52 | nvbios_extdev_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) | 52 | nvbios_extdev_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) |
53 | { | 53 | { |
54 | u8 hdr, cnt; | 54 | u8 hdr, cnt; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c index c84e93fa6d95..172a4f999990 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <subdev/bios.h> | 25 | #include <subdev/bios.h> |
26 | #include <subdev/bios/dcb.h> | 26 | #include <subdev/bios/dcb.h> |
27 | #include <subdev/bios/gpio.h> | 27 | #include <subdev/bios/gpio.h> |
28 | #include <subdev/bios/xpio.h> | ||
28 | 29 | ||
29 | u16 | 30 | u16 |
30 | dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) | 31 | dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) |
@@ -60,8 +61,14 @@ dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) | |||
60 | u16 | 61 | u16 |
61 | dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len) | 62 | dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len) |
62 | { | 63 | { |
63 | u8 hdr, cnt; | 64 | u8 hdr, cnt, xver; /* use gpio version for xpio entry parsing */ |
64 | u16 gpio = !idx ? dcb_gpio_table(bios, ver, &hdr, &cnt, len) : 0x0000; | 65 | u16 gpio; |
66 | |||
67 | if (!idx--) | ||
68 | gpio = dcb_gpio_table(bios, ver, &hdr, &cnt, len); | ||
69 | else | ||
70 | gpio = dcb_xpio_table(bios, idx, &xver, &hdr, &cnt, len); | ||
71 | |||
65 | if (gpio && ent < cnt) | 72 | if (gpio && ent < cnt) |
66 | return gpio + hdr + (ent * *len); | 73 | return gpio + hdr + (ent * *len); |
67 | return 0x0000; | 74 | return 0x0000; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c index ad577db83766..cfb9288c6d28 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c | |||
@@ -70,12 +70,12 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info) | |||
70 | u8 ver, len; | 70 | u8 ver, len; |
71 | u16 ent = dcb_i2c_entry(bios, idx, &ver, &len); | 71 | u16 ent = dcb_i2c_entry(bios, idx, &ver, &len); |
72 | if (ent) { | 72 | if (ent) { |
73 | info->data = nv_ro32(bios, ent + 0); | 73 | info->type = nv_ro08(bios, ent + 3); |
74 | info->type = nv_ro08(bios, ent + 3); | 74 | info->share = DCB_I2C_UNUSED; |
75 | if (ver < 0x30) { | 75 | if (ver < 0x30) { |
76 | info->type &= 0x07; | 76 | info->type &= 0x07; |
77 | if (info->type == 0x07) | 77 | if (info->type == 0x07) |
78 | info->type = 0xff; | 78 | info->type = DCB_I2C_UNUSED; |
79 | } | 79 | } |
80 | 80 | ||
81 | switch (info->type) { | 81 | switch (info->type) { |
@@ -88,7 +88,11 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info) | |||
88 | return 0; | 88 | return 0; |
89 | case DCB_I2C_NVIO_BIT: | 89 | case DCB_I2C_NVIO_BIT: |
90 | case DCB_I2C_NVIO_AUX: | 90 | case DCB_I2C_NVIO_AUX: |
91 | info->drive = nv_ro08(bios, ent + 0); | 91 | info->drive = nv_ro08(bios, ent + 0) & 0x0f; |
92 | if (nv_ro08(bios, ent + 1) & 0x01) { | ||
93 | info->share = nv_ro08(bios, ent + 1) >> 1; | ||
94 | info->share &= 0x0f; | ||
95 | } | ||
92 | return 0; | 96 | return 0; |
93 | case DCB_I2C_UNUSED: | 97 | case DCB_I2C_UNUSED: |
94 | return 0; | 98 | return 0; |
@@ -121,7 +125,8 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info) | |||
121 | if (!info->sense) info->sense = 0x36; | 125 | if (!info->sense) info->sense = 0x36; |
122 | } | 126 | } |
123 | 127 | ||
124 | info->type = DCB_I2C_NV04_BIT; | 128 | info->type = DCB_I2C_NV04_BIT; |
129 | info->share = DCB_I2C_UNUSED; | ||
125 | return 0; | 130 | return 0; |
126 | } | 131 | } |
127 | 132 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index 690ed438b2ad..2cc1e6a5eb6a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c | |||
@@ -231,6 +231,11 @@ init_i2c(struct nvbios_init *init, int index) | |||
231 | return NULL; | 231 | return NULL; |
232 | } | 232 | } |
233 | 233 | ||
234 | if (index == -2 && init->outp->location) { | ||
235 | index = NV_I2C_TYPE_EXTAUX(init->outp->extdev); | ||
236 | return i2c->find_type(i2c, index); | ||
237 | } | ||
238 | |||
234 | index = init->outp->i2c_index; | 239 | index = init->outp->i2c_index; |
235 | } | 240 | } |
236 | 241 | ||
@@ -258,7 +263,7 @@ init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val) | |||
258 | static int | 263 | static int |
259 | init_rdauxr(struct nvbios_init *init, u32 addr) | 264 | init_rdauxr(struct nvbios_init *init, u32 addr) |
260 | { | 265 | { |
261 | struct nouveau_i2c_port *port = init_i2c(init, -1); | 266 | struct nouveau_i2c_port *port = init_i2c(init, -2); |
262 | u8 data; | 267 | u8 data; |
263 | 268 | ||
264 | if (port && init_exec(init)) { | 269 | if (port && init_exec(init)) { |
@@ -274,7 +279,7 @@ init_rdauxr(struct nvbios_init *init, u32 addr) | |||
274 | static int | 279 | static int |
275 | init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) | 280 | init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) |
276 | { | 281 | { |
277 | struct nouveau_i2c_port *port = init_i2c(init, -1); | 282 | struct nouveau_i2c_port *port = init_i2c(init, -2); |
278 | if (port && init_exec(init)) | 283 | if (port && init_exec(init)) |
279 | return nv_wraux(port, addr, &data, 1); | 284 | return nv_wraux(port, addr, &data, 1); |
280 | return -ENODEV; | 285 | return -ENODEV; |
@@ -1816,7 +1821,7 @@ init_ram_restrict_zm_reg_group(struct nvbios_init *init) | |||
1816 | u8 i, j; | 1821 | u8 i, j; |
1817 | 1822 | ||
1818 | trace("RAM_RESTRICT_ZM_REG_GROUP\t" | 1823 | trace("RAM_RESTRICT_ZM_REG_GROUP\t" |
1819 | "R[%08x] 0x%02x 0x%02x\n", addr, incr, num); | 1824 | "R[0x%08x] 0x%02x 0x%02x\n", addr, incr, num); |
1820 | init->offset += 7; | 1825 | init->offset += 7; |
1821 | 1826 | ||
1822 | for (i = 0; i < num; i++) { | 1827 | for (i = 0; i < num; i++) { |
@@ -1849,7 +1854,7 @@ init_copy_zm_reg(struct nvbios_init *init) | |||
1849 | u32 sreg = nv_ro32(bios, init->offset + 1); | 1854 | u32 sreg = nv_ro32(bios, init->offset + 1); |
1850 | u32 dreg = nv_ro32(bios, init->offset + 5); | 1855 | u32 dreg = nv_ro32(bios, init->offset + 5); |
1851 | 1856 | ||
1852 | trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", sreg, dreg); | 1857 | trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", dreg, sreg); |
1853 | init->offset += 9; | 1858 | init->offset += 9; |
1854 | 1859 | ||
1855 | init_wr32(init, dreg, init_rd32(init, sreg)); | 1860 | init_wr32(init, dreg, init_rd32(init, sreg)); |
@@ -1866,7 +1871,7 @@ init_zm_reg_group(struct nvbios_init *init) | |||
1866 | u32 addr = nv_ro32(bios, init->offset + 1); | 1871 | u32 addr = nv_ro32(bios, init->offset + 1); |
1867 | u8 count = nv_ro08(bios, init->offset + 5); | 1872 | u8 count = nv_ro08(bios, init->offset + 5); |
1868 | 1873 | ||
1869 | trace("ZM_REG_GROUP\tR[0x%06x] =\n"); | 1874 | trace("ZM_REG_GROUP\tR[0x%06x] =\n", addr); |
1870 | init->offset += 6; | 1875 | init->offset += 6; |
1871 | 1876 | ||
1872 | while (count--) { | 1877 | while (count--) { |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c index 862a08a2ae27..22a20573ed1b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c | |||
@@ -55,7 +55,7 @@ therm_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) | |||
55 | return therm + nv_ro08(bios, therm + 1); | 55 | return therm + nv_ro08(bios, therm + 1); |
56 | } | 56 | } |
57 | 57 | ||
58 | u16 | 58 | static u16 |
59 | nvbios_therm_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) | 59 | nvbios_therm_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) |
60 | { | 60 | { |
61 | u8 hdr, cnt; | 61 | u8 hdr, cnt; |
@@ -155,10 +155,15 @@ int | |||
155 | nvbios_therm_fan_parse(struct nouveau_bios *bios, | 155 | nvbios_therm_fan_parse(struct nouveau_bios *bios, |
156 | struct nvbios_therm_fan *fan) | 156 | struct nvbios_therm_fan *fan) |
157 | { | 157 | { |
158 | struct nouveau_therm_trip_point *cur_trip = NULL; | ||
158 | u8 ver, len, i; | 159 | u8 ver, len, i; |
159 | u16 entry; | 160 | u16 entry; |
160 | 161 | ||
162 | uint8_t duty_lut[] = { 0, 0, 25, 0, 40, 0, 50, 0, | ||
163 | 75, 0, 85, 0, 100, 0, 100, 0 }; | ||
164 | |||
161 | i = 0; | 165 | i = 0; |
166 | fan->nr_fan_trip = 0; | ||
162 | while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { | 167 | while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { |
163 | s16 value = nv_ro16(bios, entry + 1); | 168 | s16 value = nv_ro16(bios, entry + 1); |
164 | 169 | ||
@@ -167,9 +172,30 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios, | |||
167 | fan->min_duty = value & 0xff; | 172 | fan->min_duty = value & 0xff; |
168 | fan->max_duty = (value & 0xff00) >> 8; | 173 | fan->max_duty = (value & 0xff00) >> 8; |
169 | break; | 174 | break; |
175 | case 0x24: | ||
176 | fan->nr_fan_trip++; | ||
177 | cur_trip = &fan->trip[fan->nr_fan_trip - 1]; | ||
178 | cur_trip->hysteresis = value & 0xf; | ||
179 | cur_trip->temp = (value & 0xff0) >> 4; | ||
180 | cur_trip->fan_duty = duty_lut[(value & 0xf000) >> 12]; | ||
181 | break; | ||
182 | case 0x25: | ||
183 | cur_trip = &fan->trip[fan->nr_fan_trip - 1]; | ||
184 | cur_trip->fan_duty = value; | ||
185 | break; | ||
170 | case 0x26: | 186 | case 0x26: |
171 | fan->pwm_freq = value; | 187 | fan->pwm_freq = value; |
172 | break; | 188 | break; |
189 | case 0x3b: | ||
190 | fan->bump_period = value; | ||
191 | break; | ||
192 | case 0x3c: | ||
193 | fan->slow_down_period = value; | ||
194 | break; | ||
195 | case 0x46: | ||
196 | fan->linear_min_temp = nv_ro08(bios, entry + 1); | ||
197 | fan->linear_max_temp = nv_ro08(bios, entry + 2); | ||
198 | break; | ||
173 | } | 199 | } |
174 | } | 200 | } |
175 | 201 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c b/drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c new file mode 100644 index 000000000000..e9b8e5d30a7a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Ben Skeggs | ||
23 | */ | ||
24 | |||
25 | #include <subdev/bios.h> | ||
26 | #include <subdev/bios/gpio.h> | ||
27 | #include <subdev/bios/xpio.h> | ||
28 | |||
29 | static u16 | ||
30 | dcb_xpiod_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) | ||
31 | { | ||
32 | u16 data = dcb_gpio_table(bios, ver, hdr, cnt, len); | ||
33 | if (data && *ver >= 0x40 && *hdr >= 0x06) { | ||
34 | u16 xpio = nv_ro16(bios, data + 0x04); | ||
35 | if (xpio) { | ||
36 | *ver = nv_ro08(bios, data + 0x00); | ||
37 | *hdr = nv_ro08(bios, data + 0x01); | ||
38 | *cnt = nv_ro08(bios, data + 0x02); | ||
39 | *len = nv_ro08(bios, data + 0x03); | ||
40 | return xpio; | ||
41 | } | ||
42 | } | ||
43 | return 0x0000; | ||
44 | } | ||
45 | |||
46 | u16 | ||
47 | dcb_xpio_table(struct nouveau_bios *bios, u8 idx, | ||
48 | u8 *ver, u8 *hdr, u8 *cnt, u8 *len) | ||
49 | { | ||
50 | u16 data = dcb_xpiod_table(bios, ver, hdr, cnt, len); | ||
51 | if (data && idx < *cnt) { | ||
52 | u16 xpio = nv_ro16(bios, data + *hdr + (idx * *len)); | ||
53 | if (xpio) { | ||
54 | *ver = nv_ro08(bios, data + 0x00); | ||
55 | *hdr = nv_ro08(bios, data + 0x01); | ||
56 | *cnt = nv_ro08(bios, data + 0x02); | ||
57 | *len = nv_ro08(bios, data + 0x03); | ||
58 | return xpio; | ||
59 | } | ||
60 | } | ||
61 | return 0x0000; | ||
62 | } | ||
63 | |||
64 | u16 | ||
65 | dcb_xpio_parse(struct nouveau_bios *bios, u8 idx, | ||
66 | u8 *ver, u8 *hdr, u8 *cnt, u8 *len, | ||
67 | struct nvbios_xpio *info) | ||
68 | { | ||
69 | u16 data = dcb_xpio_table(bios, idx, ver, hdr, cnt, len); | ||
70 | if (data && *len >= 6) { | ||
71 | info->type = nv_ro08(bios, data + 0x04); | ||
72 | info->addr = nv_ro08(bios, data + 0x05); | ||
73 | info->flags = nv_ro08(bios, data + 0x06); | ||
74 | } | ||
75 | return 0x0000; | ||
76 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c new file mode 100644 index 000000000000..8c7f8057a185 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Nouveau Community | ||
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: Martin Peres <martin.peres@labri.fr> | ||
23 | * Ben Skeggs | ||
24 | */ | ||
25 | |||
26 | #include <subdev/bus.h> | ||
27 | |||
28 | struct nv04_bus_priv { | ||
29 | struct nouveau_bus base; | ||
30 | }; | ||
31 | |||
32 | static void | ||
33 | nv04_bus_intr(struct nouveau_subdev *subdev) | ||
34 | { | ||
35 | struct nouveau_bus *pbus = nouveau_bus(subdev); | ||
36 | u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); | ||
37 | |||
38 | if (stat & 0x00000001) { | ||
39 | nv_error(pbus, "BUS ERROR\n"); | ||
40 | stat &= ~0x00000001; | ||
41 | nv_wr32(pbus, 0x001100, 0x00000001); | ||
42 | } | ||
43 | |||
44 | if (stat & 0x00000110) { | ||
45 | subdev = nouveau_subdev(subdev, NVDEV_SUBDEV_GPIO); | ||
46 | if (subdev && subdev->intr) | ||
47 | subdev->intr(subdev); | ||
48 | stat &= ~0x00000110; | ||
49 | nv_wr32(pbus, 0x001100, 0x00000110); | ||
50 | } | ||
51 | |||
52 | if (stat) { | ||
53 | nv_error(pbus, "unknown intr 0x%08x\n", stat); | ||
54 | nv_mask(pbus, 0x001140, stat, 0x00000000); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | static int | ||
59 | nv04_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
60 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
61 | struct nouveau_object **pobject) | ||
62 | { | ||
63 | struct nv04_bus_priv *priv; | ||
64 | int ret; | ||
65 | |||
66 | ret = nouveau_bus_create(parent, engine, oclass, &priv); | ||
67 | *pobject = nv_object(priv); | ||
68 | if (ret) | ||
69 | return ret; | ||
70 | |||
71 | nv_subdev(priv)->intr = nv04_bus_intr; | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int | ||
76 | nv04_bus_init(struct nouveau_object *object) | ||
77 | { | ||
78 | struct nv04_bus_priv *priv = (void *)object; | ||
79 | |||
80 | nv_wr32(priv, 0x001100, 0xffffffff); | ||
81 | nv_wr32(priv, 0x001140, 0x00000111); | ||
82 | |||
83 | return nouveau_bus_init(&priv->base); | ||
84 | } | ||
85 | |||
86 | struct nouveau_oclass | ||
87 | nv04_bus_oclass = { | ||
88 | .handle = NV_SUBDEV(BUS, 0x04), | ||
89 | .ofuncs = &(struct nouveau_ofuncs) { | ||
90 | .ctor = nv04_bus_ctor, | ||
91 | .dtor = _nouveau_bus_dtor, | ||
92 | .init = nv04_bus_init, | ||
93 | .fini = _nouveau_bus_fini, | ||
94 | }, | ||
95 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c new file mode 100644 index 000000000000..34132aef34e1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Nouveau Community | ||
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: Martin Peres <martin.peres@labri.fr> | ||
23 | * Ben Skeggs | ||
24 | */ | ||
25 | |||
26 | #include <subdev/bus.h> | ||
27 | |||
28 | struct nv31_bus_priv { | ||
29 | struct nouveau_bus base; | ||
30 | }; | ||
31 | |||
32 | static void | ||
33 | nv31_bus_intr(struct nouveau_subdev *subdev) | ||
34 | { | ||
35 | struct nouveau_bus *pbus = nouveau_bus(subdev); | ||
36 | u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); | ||
37 | u32 gpio = nv_rd32(pbus, 0x001104) & nv_rd32(pbus, 0x001144); | ||
38 | |||
39 | if (gpio) { | ||
40 | subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_GPIO); | ||
41 | if (subdev && subdev->intr) | ||
42 | subdev->intr(subdev); | ||
43 | } | ||
44 | |||
45 | if (stat & 0x00000008) { /* NV41- */ | ||
46 | u32 addr = nv_rd32(pbus, 0x009084); | ||
47 | u32 data = nv_rd32(pbus, 0x009088); | ||
48 | |||
49 | nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", | ||
50 | (addr & 0x00000002) ? "write" : "read", data, | ||
51 | (addr & 0x00fffffc)); | ||
52 | |||
53 | stat &= ~0x00000008; | ||
54 | nv_wr32(pbus, 0x001100, 0x00000008); | ||
55 | } | ||
56 | |||
57 | if (stat & 0x00070000) { | ||
58 | subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_THERM); | ||
59 | if (subdev && subdev->intr) | ||
60 | subdev->intr(subdev); | ||
61 | stat &= ~0x00070000; | ||
62 | nv_wr32(pbus, 0x001100, 0x00070000); | ||
63 | } | ||
64 | |||
65 | if (stat) { | ||
66 | nv_error(pbus, "unknown intr 0x%08x\n", stat); | ||
67 | nv_mask(pbus, 0x001140, stat, 0x00000000); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static int | ||
72 | nv31_bus_init(struct nouveau_object *object) | ||
73 | { | ||
74 | struct nv31_bus_priv *priv = (void *)object; | ||
75 | int ret; | ||
76 | |||
77 | ret = nouveau_bus_init(&priv->base); | ||
78 | if (ret) | ||
79 | return ret; | ||
80 | |||
81 | nv_wr32(priv, 0x001100, 0xffffffff); | ||
82 | nv_wr32(priv, 0x001140, 0x00070008); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int | ||
87 | nv31_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
88 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
89 | struct nouveau_object **pobject) | ||
90 | { | ||
91 | struct nv31_bus_priv *priv; | ||
92 | int ret; | ||
93 | |||
94 | ret = nouveau_bus_create(parent, engine, oclass, &priv); | ||
95 | *pobject = nv_object(priv); | ||
96 | if (ret) | ||
97 | return ret; | ||
98 | |||
99 | nv_subdev(priv)->intr = nv31_bus_intr; | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | struct nouveau_oclass | ||
104 | nv31_bus_oclass = { | ||
105 | .handle = NV_SUBDEV(BUS, 0x31), | ||
106 | .ofuncs = &(struct nouveau_ofuncs) { | ||
107 | .ctor = nv31_bus_ctor, | ||
108 | .dtor = _nouveau_bus_dtor, | ||
109 | .init = nv31_bus_init, | ||
110 | .fini = _nouveau_bus_fini, | ||
111 | }, | ||
112 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c new file mode 100644 index 000000000000..f5b2117fa8c6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Nouveau Community | ||
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: Martin Peres <martin.peres@labri.fr> | ||
23 | * Ben Skeggs | ||
24 | */ | ||
25 | |||
26 | #include <subdev/bus.h> | ||
27 | |||
28 | struct nv50_bus_priv { | ||
29 | struct nouveau_bus base; | ||
30 | }; | ||
31 | |||
32 | static void | ||
33 | nv50_bus_intr(struct nouveau_subdev *subdev) | ||
34 | { | ||
35 | struct nouveau_bus *pbus = nouveau_bus(subdev); | ||
36 | u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); | ||
37 | |||
38 | if (stat & 0x00000008) { | ||
39 | u32 addr = nv_rd32(pbus, 0x009084); | ||
40 | u32 data = nv_rd32(pbus, 0x009088); | ||
41 | |||
42 | nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", | ||
43 | (addr & 0x00000002) ? "write" : "read", data, | ||
44 | (addr & 0x00fffffc)); | ||
45 | |||
46 | stat &= ~0x00000008; | ||
47 | nv_wr32(pbus, 0x001100, 0x00000008); | ||
48 | } | ||
49 | |||
50 | if (stat & 0x00010000) { | ||
51 | subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_THERM); | ||
52 | if (subdev && subdev->intr) | ||
53 | subdev->intr(subdev); | ||
54 | stat &= ~0x00010000; | ||
55 | nv_wr32(pbus, 0x001100, 0x00010000); | ||
56 | } | ||
57 | |||
58 | if (stat) { | ||
59 | nv_error(pbus, "unknown intr 0x%08x\n", stat); | ||
60 | nv_mask(pbus, 0x001140, stat, 0); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | static int | ||
65 | nv50_bus_init(struct nouveau_object *object) | ||
66 | { | ||
67 | struct nv50_bus_priv *priv = (void *)object; | ||
68 | int ret; | ||
69 | |||
70 | ret = nouveau_bus_init(&priv->base); | ||
71 | if (ret) | ||
72 | return ret; | ||
73 | |||
74 | nv_wr32(priv, 0x001100, 0xffffffff); | ||
75 | nv_wr32(priv, 0x001140, 0x00010008); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int | ||
80 | nv50_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
81 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
82 | struct nouveau_object **pobject) | ||
83 | { | ||
84 | struct nv50_bus_priv *priv; | ||
85 | int ret; | ||
86 | |||
87 | ret = nouveau_bus_create(parent, engine, oclass, &priv); | ||
88 | *pobject = nv_object(priv); | ||
89 | if (ret) | ||
90 | return ret; | ||
91 | |||
92 | nv_subdev(priv)->intr = nv50_bus_intr; | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | struct nouveau_oclass | ||
97 | nv50_bus_oclass = { | ||
98 | .handle = NV_SUBDEV(BUS, 0x50), | ||
99 | .ofuncs = &(struct nouveau_ofuncs) { | ||
100 | .ctor = nv50_bus_ctor, | ||
101 | .dtor = _nouveau_bus_dtor, | ||
102 | .init = nv50_bus_init, | ||
103 | .fini = _nouveau_bus_fini, | ||
104 | }, | ||
105 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c new file mode 100644 index 000000000000..b192d6246363 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Nouveau Community | ||
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: Martin Peres <martin.peres@labri.fr> | ||
23 | * Ben Skeggs | ||
24 | */ | ||
25 | |||
26 | #include <subdev/bus.h> | ||
27 | |||
28 | struct nvc0_bus_priv { | ||
29 | struct nouveau_bus base; | ||
30 | }; | ||
31 | |||
32 | static void | ||
33 | nvc0_bus_intr(struct nouveau_subdev *subdev) | ||
34 | { | ||
35 | struct nouveau_bus *pbus = nouveau_bus(subdev); | ||
36 | u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); | ||
37 | |||
38 | if (stat & 0x0000000e) { | ||
39 | u32 addr = nv_rd32(pbus, 0x009084); | ||
40 | u32 data = nv_rd32(pbus, 0x009088); | ||
41 | |||
42 | nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n", | ||
43 | (addr & 0x00000002) ? "write" : "read", data, | ||
44 | (addr & 0x00fffffc), | ||
45 | (stat & 0x00000002) ? "!ENGINE " : "", | ||
46 | (stat & 0x00000004) ? "IBUS " : "", | ||
47 | (stat & 0x00000008) ? "TIMEOUT " : ""); | ||
48 | |||
49 | nv_wr32(pbus, 0x009084, 0x00000000); | ||
50 | nv_wr32(pbus, 0x001100, (stat & 0x0000000e)); | ||
51 | stat &= ~0x0000000e; | ||
52 | } | ||
53 | |||
54 | if (stat) { | ||
55 | nv_error(pbus, "unknown intr 0x%08x\n", stat); | ||
56 | nv_mask(pbus, 0x001140, stat, 0x00000000); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | static int | ||
61 | nvc0_bus_init(struct nouveau_object *object) | ||
62 | { | ||
63 | struct nvc0_bus_priv *priv = (void *)object; | ||
64 | int ret; | ||
65 | |||
66 | ret = nouveau_bus_init(&priv->base); | ||
67 | if (ret) | ||
68 | return ret; | ||
69 | |||
70 | nv_wr32(priv, 0x001100, 0xffffffff); | ||
71 | nv_wr32(priv, 0x001140, 0x0000000e); | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int | ||
76 | nvc0_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
77 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
78 | struct nouveau_object **pobject) | ||
79 | { | ||
80 | struct nvc0_bus_priv *priv; | ||
81 | int ret; | ||
82 | |||
83 | ret = nouveau_bus_create(parent, engine, oclass, &priv); | ||
84 | *pobject = nv_object(priv); | ||
85 | if (ret) | ||
86 | return ret; | ||
87 | |||
88 | nv_subdev(priv)->intr = nvc0_bus_intr; | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | struct nouveau_oclass | ||
93 | nvc0_bus_oclass = { | ||
94 | .handle = NV_SUBDEV(BUS, 0xc0), | ||
95 | .ofuncs = &(struct nouveau_ofuncs) { | ||
96 | .ctor = nvc0_bus_ctor, | ||
97 | .dtor = _nouveau_bus_dtor, | ||
98 | .init = nvc0_bus_init, | ||
99 | .fini = _nouveau_bus_fini, | ||
100 | }, | ||
101 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/base.c b/drivers/gpu/drm/nouveau/core/subdev/device/base.c index f8a7ed4166cf..3937ced5c753 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/base.c | |||
@@ -66,6 +66,7 @@ static const u64 disable_map[] = { | |||
66 | [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE, | 66 | [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE, |
67 | [NVDEV_SUBDEV_MXM] = NV_DEVICE_DISABLE_CORE, | 67 | [NVDEV_SUBDEV_MXM] = NV_DEVICE_DISABLE_CORE, |
68 | [NVDEV_SUBDEV_MC] = NV_DEVICE_DISABLE_CORE, | 68 | [NVDEV_SUBDEV_MC] = NV_DEVICE_DISABLE_CORE, |
69 | [NVDEV_SUBDEV_BUS] = NV_DEVICE_DISABLE_CORE, | ||
69 | [NVDEV_SUBDEV_TIMER] = NV_DEVICE_DISABLE_CORE, | 70 | [NVDEV_SUBDEV_TIMER] = NV_DEVICE_DISABLE_CORE, |
70 | [NVDEV_SUBDEV_FB] = NV_DEVICE_DISABLE_CORE, | 71 | [NVDEV_SUBDEV_FB] = NV_DEVICE_DISABLE_CORE, |
71 | [NVDEV_SUBDEV_LTCG] = NV_DEVICE_DISABLE_CORE, | 72 | [NVDEV_SUBDEV_LTCG] = NV_DEVICE_DISABLE_CORE, |
@@ -103,8 +104,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent, | |||
103 | struct nouveau_device *device; | 104 | struct nouveau_device *device; |
104 | struct nouveau_devobj *devobj; | 105 | struct nouveau_devobj *devobj; |
105 | struct nv_device_class *args = data; | 106 | struct nv_device_class *args = data; |
106 | u64 disable, boot0, strap; | 107 | u32 boot0, strap; |
107 | u64 mmio_base, mmio_size; | 108 | u64 disable, mmio_base, mmio_size; |
108 | void __iomem *map; | 109 | void __iomem *map; |
109 | int ret, i, c; | 110 | int ret, i, c; |
110 | 111 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c index 8626d0d6cbbc..473c5c03d3c9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <subdev/device.h> | 25 | #include <subdev/device.h> |
26 | #include <subdev/bios.h> | 26 | #include <subdev/bios.h> |
27 | #include <subdev/bus.h> | ||
27 | #include <subdev/i2c.h> | 28 | #include <subdev/i2c.h> |
28 | #include <subdev/clock.h> | 29 | #include <subdev/clock.h> |
29 | #include <subdev/devinit.h> | 30 | #include <subdev/devinit.h> |
@@ -46,10 +47,11 @@ nv04_identify(struct nouveau_device *device) | |||
46 | case 0x04: | 47 | case 0x04: |
47 | device->cname = "NV04"; | 48 | device->cname = "NV04"; |
48 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 49 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
49 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 50 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
50 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 51 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
51 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv04_devinit_oclass; | 52 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv04_devinit_oclass; |
52 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 53 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
54 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
53 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 55 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
54 | device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass; | 56 | device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass; |
55 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 57 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -63,10 +65,11 @@ nv04_identify(struct nouveau_device *device) | |||
63 | case 0x05: | 65 | case 0x05: |
64 | device->cname = "NV05"; | 66 | device->cname = "NV05"; |
65 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 67 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
66 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 68 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
67 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 69 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
68 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv05_devinit_oclass; | 70 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv05_devinit_oclass; |
69 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 71 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
72 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
70 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 73 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
71 | device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass; | 74 | device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass; |
72 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 75 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c index 9c40b0fb23f6..d0774f5bebe1 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <subdev/device.h> | 25 | #include <subdev/device.h> |
26 | #include <subdev/bios.h> | 26 | #include <subdev/bios.h> |
27 | #include <subdev/bus.h> | ||
27 | #include <subdev/gpio.h> | 28 | #include <subdev/gpio.h> |
28 | #include <subdev/i2c.h> | 29 | #include <subdev/i2c.h> |
29 | #include <subdev/clock.h> | 30 | #include <subdev/clock.h> |
@@ -48,10 +49,11 @@ nv10_identify(struct nouveau_device *device) | |||
48 | device->cname = "NV10"; | 49 | device->cname = "NV10"; |
49 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 50 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
50 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 51 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
51 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 52 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
52 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 53 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
53 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; | 54 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; |
54 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 55 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
56 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
55 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 57 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
56 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; | 58 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; |
57 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 59 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -64,10 +66,11 @@ nv10_identify(struct nouveau_device *device) | |||
64 | device->cname = "NV15"; | 66 | device->cname = "NV15"; |
65 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 67 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
66 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 68 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
67 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 69 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
68 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 70 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
69 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; | 71 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; |
70 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 72 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
73 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
71 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 74 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
72 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; | 75 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; |
73 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 76 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -82,10 +85,11 @@ nv10_identify(struct nouveau_device *device) | |||
82 | device->cname = "NV16"; | 85 | device->cname = "NV16"; |
83 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 86 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
84 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 87 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
85 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 88 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
86 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 89 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
87 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; | 90 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; |
88 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 91 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
92 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
89 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 93 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
90 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; | 94 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; |
91 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 95 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -100,10 +104,11 @@ nv10_identify(struct nouveau_device *device) | |||
100 | device->cname = "nForce"; | 104 | device->cname = "nForce"; |
101 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 105 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
102 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 106 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
103 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 107 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
104 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 108 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
105 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 109 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
106 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 110 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
111 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
107 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 112 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
108 | device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass; | 113 | device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass; |
109 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 114 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -118,10 +123,11 @@ nv10_identify(struct nouveau_device *device) | |||
118 | device->cname = "NV11"; | 123 | device->cname = "NV11"; |
119 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 124 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
120 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 125 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
121 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 126 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
122 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 127 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
123 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; | 128 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; |
124 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 129 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
130 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
125 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 131 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
126 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; | 132 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; |
127 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 133 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -136,10 +142,11 @@ nv10_identify(struct nouveau_device *device) | |||
136 | device->cname = "NV17"; | 142 | device->cname = "NV17"; |
137 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 143 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
138 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 144 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
139 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 145 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
140 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 146 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
141 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; | 147 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; |
142 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 148 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
149 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
143 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 150 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
144 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; | 151 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; |
145 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 152 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -154,10 +161,11 @@ nv10_identify(struct nouveau_device *device) | |||
154 | device->cname = "nForce2"; | 161 | device->cname = "nForce2"; |
155 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 162 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
156 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 163 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
157 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 164 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
158 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 165 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
159 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 166 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
160 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 167 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
168 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
161 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 169 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
162 | device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass; | 170 | device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass; |
163 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 171 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -172,10 +180,11 @@ nv10_identify(struct nouveau_device *device) | |||
172 | device->cname = "NV18"; | 180 | device->cname = "NV18"; |
173 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 181 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
174 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 182 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
175 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 183 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
176 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 184 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
177 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; | 185 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; |
178 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 186 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
187 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
179 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 188 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
180 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; | 189 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; |
181 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 190 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c index 74f88f48e1c2..ab920e0dc45b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <subdev/device.h> | 25 | #include <subdev/device.h> |
26 | #include <subdev/bios.h> | 26 | #include <subdev/bios.h> |
27 | #include <subdev/bus.h> | ||
27 | #include <subdev/gpio.h> | 28 | #include <subdev/gpio.h> |
28 | #include <subdev/i2c.h> | 29 | #include <subdev/i2c.h> |
29 | #include <subdev/clock.h> | 30 | #include <subdev/clock.h> |
@@ -49,10 +50,11 @@ nv20_identify(struct nouveau_device *device) | |||
49 | device->cname = "NV20"; | 50 | device->cname = "NV20"; |
50 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 51 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
51 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 52 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
52 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 53 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
53 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 54 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
54 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; | 55 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; |
55 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 56 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
57 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
56 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 58 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
57 | device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; | 59 | device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; |
58 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 60 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -67,10 +69,11 @@ nv20_identify(struct nouveau_device *device) | |||
67 | device->cname = "NV25"; | 69 | device->cname = "NV25"; |
68 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 70 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
69 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 71 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
70 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 72 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
71 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 73 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
72 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; | 74 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; |
73 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 75 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
76 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
74 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 77 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
75 | device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass; | 78 | device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass; |
76 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 79 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -85,10 +88,11 @@ nv20_identify(struct nouveau_device *device) | |||
85 | device->cname = "NV28"; | 88 | device->cname = "NV28"; |
86 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 89 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
87 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 90 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
88 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 91 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
89 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 92 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
90 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; | 93 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; |
91 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 94 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
95 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
92 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 96 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
93 | device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass; | 97 | device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass; |
94 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 98 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -103,10 +107,11 @@ nv20_identify(struct nouveau_device *device) | |||
103 | device->cname = "NV2A"; | 107 | device->cname = "NV2A"; |
104 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 108 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
105 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 109 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
106 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 110 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
107 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 111 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
108 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; | 112 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; |
109 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 113 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
114 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
110 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 115 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
111 | device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass; | 116 | device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass; |
112 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 117 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c index 0ac1b2c4f61d..5f2110261b04 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <subdev/device.h> | 25 | #include <subdev/device.h> |
26 | #include <subdev/bios.h> | 26 | #include <subdev/bios.h> |
27 | #include <subdev/bus.h> | ||
27 | #include <subdev/gpio.h> | 28 | #include <subdev/gpio.h> |
28 | #include <subdev/i2c.h> | 29 | #include <subdev/i2c.h> |
29 | #include <subdev/clock.h> | 30 | #include <subdev/clock.h> |
@@ -49,10 +50,11 @@ nv30_identify(struct nouveau_device *device) | |||
49 | device->cname = "NV30"; | 50 | device->cname = "NV30"; |
50 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 51 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
51 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 52 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
52 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 53 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
53 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 54 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
54 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; | 55 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; |
55 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 56 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
57 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
56 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 58 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
57 | device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; | 59 | device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; |
58 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 60 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -67,10 +69,11 @@ nv30_identify(struct nouveau_device *device) | |||
67 | device->cname = "NV35"; | 69 | device->cname = "NV35"; |
68 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 70 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
69 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 71 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
70 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 72 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
71 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 73 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
72 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; | 74 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; |
73 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 75 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
76 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; | ||
74 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 77 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
75 | device->oclass[NVDEV_SUBDEV_FB ] = &nv35_fb_oclass; | 78 | device->oclass[NVDEV_SUBDEV_FB ] = &nv35_fb_oclass; |
76 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 79 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -85,10 +88,11 @@ nv30_identify(struct nouveau_device *device) | |||
85 | device->cname = "NV31"; | 88 | device->cname = "NV31"; |
86 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 89 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
87 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 90 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
88 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 91 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
89 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 92 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
90 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; | 93 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; |
91 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 94 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
95 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
92 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 96 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
93 | device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; | 97 | device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; |
94 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 98 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -104,10 +108,11 @@ nv30_identify(struct nouveau_device *device) | |||
104 | device->cname = "NV36"; | 108 | device->cname = "NV36"; |
105 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 109 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
106 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 110 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
107 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 111 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
108 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 112 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
109 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; | 113 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; |
110 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 114 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
115 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
111 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 116 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
112 | device->oclass[NVDEV_SUBDEV_FB ] = &nv36_fb_oclass; | 117 | device->oclass[NVDEV_SUBDEV_FB ] = &nv36_fb_oclass; |
113 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 118 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
@@ -123,10 +128,11 @@ nv30_identify(struct nouveau_device *device) | |||
123 | device->cname = "NV34"; | 128 | device->cname = "NV34"; |
124 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 129 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
125 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 130 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
126 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 131 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
127 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; | 132 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; |
128 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; | 133 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; |
129 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 134 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
135 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
130 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 136 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
131 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; | 137 | device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; |
132 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; | 138 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c index 41d59689a021..f3d55efe9ac9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c | |||
@@ -24,6 +24,8 @@ | |||
24 | 24 | ||
25 | #include <subdev/device.h> | 25 | #include <subdev/device.h> |
26 | #include <subdev/bios.h> | 26 | #include <subdev/bios.h> |
27 | #include <subdev/bus.h> | ||
28 | #include <subdev/vm.h> | ||
27 | #include <subdev/gpio.h> | 29 | #include <subdev/gpio.h> |
28 | #include <subdev/i2c.h> | 30 | #include <subdev/i2c.h> |
29 | #include <subdev/clock.h> | 31 | #include <subdev/clock.h> |
@@ -50,11 +52,12 @@ nv40_identify(struct nouveau_device *device) | |||
50 | device->cname = "NV40"; | 52 | device->cname = "NV40"; |
51 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 53 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
52 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 54 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
53 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 55 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
54 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 56 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
55 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 57 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
56 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 58 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
57 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 59 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
60 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
58 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 61 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
59 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; | 62 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; |
60 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 63 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -70,11 +73,12 @@ nv40_identify(struct nouveau_device *device) | |||
70 | device->cname = "NV41"; | 73 | device->cname = "NV41"; |
71 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 74 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
72 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 75 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
73 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 76 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
74 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 77 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
75 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 78 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
76 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 79 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
77 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 80 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
81 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
78 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 82 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
79 | device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass; | 83 | device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass; |
80 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 84 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -90,11 +94,12 @@ nv40_identify(struct nouveau_device *device) | |||
90 | device->cname = "NV42"; | 94 | device->cname = "NV42"; |
91 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 95 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
92 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 96 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
93 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 97 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
94 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 98 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
95 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 99 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
96 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 100 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
97 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 101 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
102 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
98 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 103 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
99 | device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass; | 104 | device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass; |
100 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 105 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -110,11 +115,12 @@ nv40_identify(struct nouveau_device *device) | |||
110 | device->cname = "NV43"; | 115 | device->cname = "NV43"; |
111 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 116 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
112 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 117 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
113 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 118 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
114 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 119 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
115 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 120 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
116 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 121 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
117 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 122 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
123 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
118 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 124 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
119 | device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass; | 125 | device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass; |
120 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 126 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -130,11 +136,12 @@ nv40_identify(struct nouveau_device *device) | |||
130 | device->cname = "NV45"; | 136 | device->cname = "NV45"; |
131 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 137 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
132 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 138 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
133 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 139 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
134 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 140 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
135 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 141 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
136 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 142 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
137 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 143 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
144 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
138 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 145 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
139 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; | 146 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; |
140 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 147 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -150,11 +157,12 @@ nv40_identify(struct nouveau_device *device) | |||
150 | device->cname = "G70"; | 157 | device->cname = "G70"; |
151 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 158 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
152 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 159 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
153 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 160 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
154 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 161 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
155 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 162 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
156 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 163 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
157 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 164 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
165 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
158 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 166 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
159 | device->oclass[NVDEV_SUBDEV_FB ] = &nv47_fb_oclass; | 167 | device->oclass[NVDEV_SUBDEV_FB ] = &nv47_fb_oclass; |
160 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 168 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -170,11 +178,12 @@ nv40_identify(struct nouveau_device *device) | |||
170 | device->cname = "G71"; | 178 | device->cname = "G71"; |
171 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 179 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
172 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 180 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
173 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 181 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
174 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 182 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
175 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 183 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
176 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 184 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
177 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 185 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
186 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
178 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 187 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
179 | device->oclass[NVDEV_SUBDEV_FB ] = &nv49_fb_oclass; | 188 | device->oclass[NVDEV_SUBDEV_FB ] = &nv49_fb_oclass; |
180 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 189 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -190,11 +199,12 @@ nv40_identify(struct nouveau_device *device) | |||
190 | device->cname = "G73"; | 199 | device->cname = "G73"; |
191 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 200 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
192 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 201 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
193 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 202 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
194 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 203 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
195 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 204 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
196 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 205 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
197 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; | 206 | device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; |
207 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
198 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 208 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
199 | device->oclass[NVDEV_SUBDEV_FB ] = &nv49_fb_oclass; | 209 | device->oclass[NVDEV_SUBDEV_FB ] = &nv49_fb_oclass; |
200 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 210 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -210,11 +220,12 @@ nv40_identify(struct nouveau_device *device) | |||
210 | device->cname = "NV44"; | 220 | device->cname = "NV44"; |
211 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 221 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
212 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 222 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
213 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 223 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
214 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 224 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
215 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 225 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
216 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 226 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
217 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; | 227 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; |
228 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
218 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 229 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
219 | device->oclass[NVDEV_SUBDEV_FB ] = &nv44_fb_oclass; | 230 | device->oclass[NVDEV_SUBDEV_FB ] = &nv44_fb_oclass; |
220 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 231 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -230,11 +241,12 @@ nv40_identify(struct nouveau_device *device) | |||
230 | device->cname = "G72"; | 241 | device->cname = "G72"; |
231 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 242 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
232 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 243 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
233 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 244 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
234 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 245 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
235 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 246 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
236 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 247 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
237 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; | 248 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; |
249 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
238 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 250 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
239 | device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; | 251 | device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; |
240 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 252 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -250,11 +262,12 @@ nv40_identify(struct nouveau_device *device) | |||
250 | device->cname = "NV44A"; | 262 | device->cname = "NV44A"; |
251 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 263 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
252 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 264 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
253 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 265 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
254 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 266 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
255 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 267 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
256 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 268 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
257 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; | 269 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; |
270 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
258 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 271 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
259 | device->oclass[NVDEV_SUBDEV_FB ] = &nv44_fb_oclass; | 272 | device->oclass[NVDEV_SUBDEV_FB ] = &nv44_fb_oclass; |
260 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 273 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -270,11 +283,12 @@ nv40_identify(struct nouveau_device *device) | |||
270 | device->cname = "C61"; | 283 | device->cname = "C61"; |
271 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 284 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
272 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 285 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
273 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 286 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
274 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 287 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
275 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 288 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
276 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 289 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
277 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; | 290 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; |
291 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
278 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 292 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
279 | device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; | 293 | device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; |
280 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 294 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -290,11 +304,12 @@ nv40_identify(struct nouveau_device *device) | |||
290 | device->cname = "C51"; | 304 | device->cname = "C51"; |
291 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 305 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
292 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 306 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
293 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 307 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv4e_i2c_oclass; |
294 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 308 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
295 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 309 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
296 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 310 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
297 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; | 311 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; |
312 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
298 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 313 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
299 | device->oclass[NVDEV_SUBDEV_FB ] = &nv4e_fb_oclass; | 314 | device->oclass[NVDEV_SUBDEV_FB ] = &nv4e_fb_oclass; |
300 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 315 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -310,11 +325,12 @@ nv40_identify(struct nouveau_device *device) | |||
310 | device->cname = "C73"; | 325 | device->cname = "C73"; |
311 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 326 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
312 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 327 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
313 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 328 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
314 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 329 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
315 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 330 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
316 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 331 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
317 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; | 332 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; |
333 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
318 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 334 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
319 | device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; | 335 | device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; |
320 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 336 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -330,11 +346,12 @@ nv40_identify(struct nouveau_device *device) | |||
330 | device->cname = "C67"; | 346 | device->cname = "C67"; |
331 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 347 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
332 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 348 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
333 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 349 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
334 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 350 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
335 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 351 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
336 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 352 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
337 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; | 353 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; |
354 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
338 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 355 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
339 | device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; | 356 | device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; |
340 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 357 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
@@ -350,11 +367,12 @@ nv40_identify(struct nouveau_device *device) | |||
350 | device->cname = "C68"; | 367 | device->cname = "C68"; |
351 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 368 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
352 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; | 369 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; |
353 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 370 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; |
354 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; | 371 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; |
355 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; | 372 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; |
356 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; | 373 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; |
357 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; | 374 | device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; |
375 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; | ||
358 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 376 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
359 | device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; | 377 | device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; |
360 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 378 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c index 6ccfd8585ba2..5ed2fa51ddc2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <subdev/device.h> | 25 | #include <subdev/device.h> |
26 | #include <subdev/bios.h> | 26 | #include <subdev/bios.h> |
27 | #include <subdev/bus.h> | ||
27 | #include <subdev/gpio.h> | 28 | #include <subdev/gpio.h> |
28 | #include <subdev/i2c.h> | 29 | #include <subdev/i2c.h> |
29 | #include <subdev/clock.h> | 30 | #include <subdev/clock.h> |
@@ -57,12 +58,13 @@ nv50_identify(struct nouveau_device *device) | |||
57 | device->cname = "G80"; | 58 | device->cname = "G80"; |
58 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 59 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
59 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 60 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
60 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 61 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; |
61 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; | 62 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; |
62 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 63 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; |
63 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 64 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
64 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 65 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
65 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; | 66 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; |
67 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
66 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 68 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
67 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 69 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
68 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 70 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -79,12 +81,13 @@ nv50_identify(struct nouveau_device *device) | |||
79 | device->cname = "G84"; | 81 | device->cname = "G84"; |
80 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 82 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
81 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 83 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
82 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 84 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; |
83 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; | 85 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; |
84 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 86 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; |
85 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 87 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
86 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 88 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
87 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; | 89 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; |
90 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
88 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 91 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
89 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 92 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
90 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 93 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -104,12 +107,13 @@ nv50_identify(struct nouveau_device *device) | |||
104 | device->cname = "G86"; | 107 | device->cname = "G86"; |
105 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 108 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
106 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 109 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
107 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 110 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; |
108 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; | 111 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; |
109 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 112 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; |
110 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 113 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
111 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 114 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
112 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; | 115 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; |
116 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
113 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 117 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
114 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 118 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
115 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 119 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -129,12 +133,13 @@ nv50_identify(struct nouveau_device *device) | |||
129 | device->cname = "G92"; | 133 | device->cname = "G92"; |
130 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 134 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
131 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 135 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
132 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 136 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; |
133 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; | 137 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; |
134 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 138 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; |
135 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 139 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
136 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 140 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
137 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; | 141 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; |
142 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
138 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 143 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
139 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 144 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
140 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 145 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -154,12 +159,13 @@ nv50_identify(struct nouveau_device *device) | |||
154 | device->cname = "G94"; | 159 | device->cname = "G94"; |
155 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 160 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
156 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 161 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
157 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 162 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
158 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; | 163 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; |
159 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 164 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; |
160 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 165 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
161 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 166 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
162 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; | 167 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; |
168 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
163 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 169 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
164 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 170 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
165 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 171 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -179,12 +185,13 @@ nv50_identify(struct nouveau_device *device) | |||
179 | device->cname = "G96"; | 185 | device->cname = "G96"; |
180 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 186 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
181 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 187 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
182 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 188 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
183 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; | 189 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; |
184 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 190 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; |
185 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 191 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
186 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 192 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
187 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; | 193 | device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; |
194 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
188 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 195 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
189 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 196 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
190 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 197 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -204,12 +211,13 @@ nv50_identify(struct nouveau_device *device) | |||
204 | device->cname = "G98"; | 211 | device->cname = "G98"; |
205 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 212 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
206 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 213 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
207 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 214 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
208 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; | 215 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; |
209 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 216 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; |
210 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 217 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
211 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 218 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
212 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; | 219 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; |
220 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
213 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 221 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
214 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 222 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
215 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 223 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -229,12 +237,13 @@ nv50_identify(struct nouveau_device *device) | |||
229 | device->cname = "G200"; | 237 | device->cname = "G200"; |
230 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 238 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
231 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 239 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
232 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 240 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; |
233 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; | 241 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; |
234 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 242 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; |
235 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 243 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
236 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 244 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
237 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; | 245 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; |
246 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
238 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 247 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
239 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 248 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
240 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 249 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -254,12 +263,13 @@ nv50_identify(struct nouveau_device *device) | |||
254 | device->cname = "MCP77/MCP78"; | 263 | device->cname = "MCP77/MCP78"; |
255 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 264 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
256 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 265 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
257 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 266 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
258 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; | 267 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; |
259 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 268 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; |
260 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 269 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
261 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 270 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
262 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; | 271 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; |
272 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
263 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 273 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
264 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 274 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
265 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 275 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -279,12 +289,13 @@ nv50_identify(struct nouveau_device *device) | |||
279 | device->cname = "MCP79/MCP7A"; | 289 | device->cname = "MCP79/MCP7A"; |
280 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 290 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
281 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 291 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
282 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 292 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
283 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; | 293 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; |
284 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 294 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; |
285 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 295 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
286 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 296 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
287 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; | 297 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; |
298 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
288 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 299 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
289 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 300 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
290 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 301 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -304,12 +315,13 @@ nv50_identify(struct nouveau_device *device) | |||
304 | device->cname = "GT215"; | 315 | device->cname = "GT215"; |
305 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 316 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
306 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 317 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
307 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 318 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
308 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; | 319 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; |
309 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 320 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
310 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 321 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
311 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 322 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
312 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; | 323 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; |
324 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
313 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 325 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
314 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 326 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
315 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 327 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -330,12 +342,13 @@ nv50_identify(struct nouveau_device *device) | |||
330 | device->cname = "GT216"; | 342 | device->cname = "GT216"; |
331 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 343 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
332 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 344 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
333 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 345 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
334 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; | 346 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; |
335 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 347 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
336 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 348 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
337 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 349 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
338 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; | 350 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; |
351 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
339 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 352 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
340 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 353 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
341 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 354 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -355,12 +368,13 @@ nv50_identify(struct nouveau_device *device) | |||
355 | device->cname = "GT218"; | 368 | device->cname = "GT218"; |
356 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 369 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
357 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 370 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
358 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 371 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
359 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; | 372 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; |
360 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 373 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
361 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 374 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
362 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 375 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
363 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; | 376 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; |
377 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
364 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 378 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
365 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 379 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
366 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 380 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
@@ -380,12 +394,13 @@ nv50_identify(struct nouveau_device *device) | |||
380 | device->cname = "MCP89"; | 394 | device->cname = "MCP89"; |
381 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 395 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
382 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 396 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
383 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 397 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
384 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; | 398 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; |
385 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 399 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
386 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 400 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
387 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 401 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
388 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; | 402 | device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; |
403 | device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; | ||
389 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 404 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
390 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; | 405 | device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; |
391 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; | 406 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c index f0461685a422..4393eb4d6564 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <subdev/device.h> | 25 | #include <subdev/device.h> |
26 | #include <subdev/bios.h> | 26 | #include <subdev/bios.h> |
27 | #include <subdev/bus.h> | ||
27 | #include <subdev/gpio.h> | 28 | #include <subdev/gpio.h> |
28 | #include <subdev/i2c.h> | 29 | #include <subdev/i2c.h> |
29 | #include <subdev/clock.h> | 30 | #include <subdev/clock.h> |
@@ -57,12 +58,13 @@ nvc0_identify(struct nouveau_device *device) | |||
57 | device->cname = "GF100"; | 58 | device->cname = "GF100"; |
58 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 59 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
59 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 60 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
60 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 61 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
61 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 62 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
62 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 63 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
63 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 64 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
64 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 65 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
65 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 66 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
67 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
66 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 68 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
67 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 69 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
68 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 70 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
@@ -85,12 +87,13 @@ nvc0_identify(struct nouveau_device *device) | |||
85 | device->cname = "GF104"; | 87 | device->cname = "GF104"; |
86 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 88 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
87 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 89 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
88 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 90 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
89 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 91 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
90 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 92 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
91 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 93 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
92 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 94 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
93 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 95 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
96 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
94 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 97 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
95 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 98 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
96 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 99 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
@@ -113,12 +116,13 @@ nvc0_identify(struct nouveau_device *device) | |||
113 | device->cname = "GF106"; | 116 | device->cname = "GF106"; |
114 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 117 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
115 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 118 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
116 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 119 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
117 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 120 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
118 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 121 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
119 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 122 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
120 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 123 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
121 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 124 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
125 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
122 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 126 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
123 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 127 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
124 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 128 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
@@ -141,12 +145,13 @@ nvc0_identify(struct nouveau_device *device) | |||
141 | device->cname = "GF114"; | 145 | device->cname = "GF114"; |
142 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 146 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
143 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 147 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
144 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 148 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
145 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 149 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
146 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 150 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
147 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 151 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
148 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 152 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
149 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 153 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
154 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
150 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 155 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
151 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 156 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
152 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 157 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
@@ -169,12 +174,13 @@ nvc0_identify(struct nouveau_device *device) | |||
169 | device->cname = "GF116"; | 174 | device->cname = "GF116"; |
170 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 175 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
171 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 176 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
172 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 177 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
173 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 178 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
174 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 179 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
175 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 180 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
176 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 181 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
177 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 182 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
183 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
178 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 184 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
179 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 185 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
180 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 186 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
@@ -197,12 +203,13 @@ nvc0_identify(struct nouveau_device *device) | |||
197 | device->cname = "GF108"; | 203 | device->cname = "GF108"; |
198 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 204 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
199 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 205 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
200 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 206 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
201 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 207 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
202 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 208 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
203 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 209 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
204 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 210 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
205 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 211 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
212 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
206 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 213 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
207 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 214 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
208 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 215 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
@@ -225,12 +232,13 @@ nvc0_identify(struct nouveau_device *device) | |||
225 | device->cname = "GF110"; | 232 | device->cname = "GF110"; |
226 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 233 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
227 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 234 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
228 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 235 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
229 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 236 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
230 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 237 | device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; |
231 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 238 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
232 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 239 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
233 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 240 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
241 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
234 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 242 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
235 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 243 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
236 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 244 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
@@ -253,12 +261,13 @@ nvc0_identify(struct nouveau_device *device) | |||
253 | device->cname = "GF119"; | 261 | device->cname = "GF119"; |
254 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 262 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
255 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; | 263 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; |
256 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 264 | device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; |
257 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 265 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
258 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 266 | device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; |
259 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 267 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
260 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 268 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
261 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 269 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
270 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
262 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 271 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
263 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 272 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
264 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 273 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
@@ -282,4 +291,4 @@ nvc0_identify(struct nouveau_device *device) | |||
282 | } | 291 | } |
283 | 292 | ||
284 | return 0; | 293 | return 0; |
285 | } | 294 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c index 03a652876e73..5c12391619fd 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <subdev/device.h> | 25 | #include <subdev/device.h> |
26 | #include <subdev/bios.h> | 26 | #include <subdev/bios.h> |
27 | #include <subdev/bus.h> | ||
27 | #include <subdev/gpio.h> | 28 | #include <subdev/gpio.h> |
28 | #include <subdev/i2c.h> | 29 | #include <subdev/i2c.h> |
29 | #include <subdev/clock.h> | 30 | #include <subdev/clock.h> |
@@ -56,13 +57,14 @@ nve0_identify(struct nouveau_device *device) | |||
56 | case 0xe4: | 57 | case 0xe4: |
57 | device->cname = "GK104"; | 58 | device->cname = "GK104"; |
58 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 59 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
59 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; | 60 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; |
60 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 61 | device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; |
61 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 62 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
62 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 63 | device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; |
63 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 64 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
64 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 65 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
65 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 66 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
67 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
66 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 68 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
67 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 69 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
68 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 70 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
@@ -84,13 +86,14 @@ nve0_identify(struct nouveau_device *device) | |||
84 | case 0xe7: | 86 | case 0xe7: |
85 | device->cname = "GK107"; | 87 | device->cname = "GK107"; |
86 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 88 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
87 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; | 89 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; |
88 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 90 | device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; |
89 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 91 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
90 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 92 | device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; |
91 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 93 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
92 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 94 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
93 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 95 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
96 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
94 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 97 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
95 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 98 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
96 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 99 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
@@ -112,13 +115,14 @@ nve0_identify(struct nouveau_device *device) | |||
112 | case 0xe6: | 115 | case 0xe6: |
113 | device->cname = "GK106"; | 116 | device->cname = "GK106"; |
114 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 117 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
115 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; | 118 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; |
116 | device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; | 119 | device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; |
117 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; | 120 | device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; |
118 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; | 121 | device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; |
119 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 122 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
120 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 123 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
121 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; | 124 | device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; |
125 | device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; | ||
122 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 126 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
123 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; | 127 | device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; |
124 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; | 128 | device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c index ae7249b09797..4a8577838417 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c | |||
@@ -78,12 +78,13 @@ nv50_devinit_init(struct nouveau_object *object) | |||
78 | if (ret) | 78 | if (ret) |
79 | return ret; | 79 | return ret; |
80 | 80 | ||
81 | /* if we ran the init tables, execute first script pointer for each | 81 | /* if we ran the init tables, we have to execute the first script |
82 | * display table output entry that has a matching dcb entry. | 82 | * pointer of each dcb entry's display encoder table in order |
83 | * to properly initialise each encoder. | ||
83 | */ | 84 | */ |
84 | while (priv->base.post && ver) { | 85 | while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { |
85 | u16 data = nvbios_outp_parse(bios, i++, &ver, &hdr, &cnt, &len, &info); | 86 | if (nvbios_outp_match(bios, outp.hasht, outp.hashm, |
86 | if (data && dcb_outp_match(bios, info.type, info.mask, &ver, &len, &outp)) { | 87 | &ver, &hdr, &cnt, &len, &info)) { |
87 | struct nvbios_init init = { | 88 | struct nvbios_init init = { |
88 | .subdev = nv_subdev(priv), | 89 | .subdev = nv_subdev(priv), |
89 | .bios = bios, | 90 | .bios = bios, |
@@ -95,7 +96,8 @@ nv50_devinit_init(struct nouveau_object *object) | |||
95 | 96 | ||
96 | nvbios_exec(&init); | 97 | nvbios_exec(&init); |
97 | } | 98 | } |
98 | }; | 99 | i++; |
100 | } | ||
99 | 101 | ||
100 | return 0; | 102 | return 0; |
101 | } | 103 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c index 487cb8c6c204..a4338d92b02e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c | |||
@@ -22,8 +22,10 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/object.h> | 25 | #include <core/client.h> |
26 | #include <core/enum.h> | 26 | #include <core/enum.h> |
27 | #include <core/engctx.h> | ||
28 | #include <core/object.h> | ||
27 | 29 | ||
28 | #include <subdev/fb.h> | 30 | #include <subdev/fb.h> |
29 | #include <subdev/bios.h> | 31 | #include <subdev/bios.h> |
@@ -302,17 +304,18 @@ static const struct nouveau_enum vm_client[] = { | |||
302 | }; | 304 | }; |
303 | 305 | ||
304 | static const struct nouveau_enum vm_engine[] = { | 306 | static const struct nouveau_enum vm_engine[] = { |
305 | { 0x00000000, "PGRAPH", NULL }, | 307 | { 0x00000000, "PGRAPH", NULL, NVDEV_ENGINE_GR }, |
306 | { 0x00000001, "PVP", NULL }, | 308 | { 0x00000001, "PVP", NULL, NVDEV_ENGINE_VP }, |
307 | { 0x00000004, "PEEPHOLE", NULL }, | 309 | { 0x00000004, "PEEPHOLE", NULL }, |
308 | { 0x00000005, "PFIFO", vm_pfifo_subclients }, | 310 | { 0x00000005, "PFIFO", vm_pfifo_subclients, NVDEV_ENGINE_FIFO }, |
309 | { 0x00000006, "BAR", vm_bar_subclients }, | 311 | { 0x00000006, "BAR", vm_bar_subclients }, |
310 | { 0x00000008, "PPPP", NULL }, | 312 | { 0x00000008, "PPPP", NULL, NVDEV_ENGINE_PPP }, |
311 | { 0x00000009, "PBSP", NULL }, | 313 | { 0x00000008, "PMPEG", NULL, NVDEV_ENGINE_MPEG }, |
312 | { 0x0000000a, "PCRYPT", NULL }, | 314 | { 0x00000009, "PBSP", NULL, NVDEV_ENGINE_BSP }, |
315 | { 0x0000000a, "PCRYPT", NULL, NVDEV_ENGINE_CRYPT }, | ||
313 | { 0x0000000b, "PCOUNTER", NULL }, | 316 | { 0x0000000b, "PCOUNTER", NULL }, |
314 | { 0x0000000c, "SEMAPHORE_BG", NULL }, | 317 | { 0x0000000c, "SEMAPHORE_BG", NULL }, |
315 | { 0x0000000d, "PCOPY", NULL }, | 318 | { 0x0000000d, "PCOPY", NULL, NVDEV_ENGINE_COPY0 }, |
316 | { 0x0000000e, "PDAEMON", NULL }, | 319 | { 0x0000000e, "PDAEMON", NULL }, |
317 | {} | 320 | {} |
318 | }; | 321 | }; |
@@ -334,8 +337,10 @@ static void | |||
334 | nv50_fb_intr(struct nouveau_subdev *subdev) | 337 | nv50_fb_intr(struct nouveau_subdev *subdev) |
335 | { | 338 | { |
336 | struct nouveau_device *device = nv_device(subdev); | 339 | struct nouveau_device *device = nv_device(subdev); |
340 | struct nouveau_engine *engine; | ||
337 | struct nv50_fb_priv *priv = (void *)subdev; | 341 | struct nv50_fb_priv *priv = (void *)subdev; |
338 | const struct nouveau_enum *en, *cl; | 342 | const struct nouveau_enum *en, *cl; |
343 | struct nouveau_object *engctx = NULL; | ||
339 | u32 trap[6], idx, chan; | 344 | u32 trap[6], idx, chan; |
340 | u8 st0, st1, st2, st3; | 345 | u8 st0, st1, st2, st3; |
341 | int i; | 346 | int i; |
@@ -366,36 +371,55 @@ nv50_fb_intr(struct nouveau_subdev *subdev) | |||
366 | } | 371 | } |
367 | chan = (trap[2] << 16) | trap[1]; | 372 | chan = (trap[2] << 16) | trap[1]; |
368 | 373 | ||
369 | nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x ", | 374 | en = nouveau_enum_find(vm_engine, st0); |
375 | |||
376 | if (en && en->data2) { | ||
377 | const struct nouveau_enum *orig_en = en; | ||
378 | while (en->name && en->value == st0 && en->data2) { | ||
379 | engine = nouveau_engine(subdev, en->data2); | ||
380 | if (engine) { | ||
381 | engctx = nouveau_engctx_get(engine, chan); | ||
382 | if (engctx) | ||
383 | break; | ||
384 | } | ||
385 | en++; | ||
386 | } | ||
387 | if (!engctx) | ||
388 | en = orig_en; | ||
389 | } | ||
390 | |||
391 | nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ", | ||
370 | (trap[5] & 0x00000100) ? "read" : "write", | 392 | (trap[5] & 0x00000100) ? "read" : "write", |
371 | trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan); | 393 | trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan, |
394 | nouveau_client_name(engctx)); | ||
395 | |||
396 | nouveau_engctx_put(engctx); | ||
372 | 397 | ||
373 | en = nouveau_enum_find(vm_engine, st0); | ||
374 | if (en) | 398 | if (en) |
375 | printk("%s/", en->name); | 399 | pr_cont("%s/", en->name); |
376 | else | 400 | else |
377 | printk("%02x/", st0); | 401 | pr_cont("%02x/", st0); |
378 | 402 | ||
379 | cl = nouveau_enum_find(vm_client, st2); | 403 | cl = nouveau_enum_find(vm_client, st2); |
380 | if (cl) | 404 | if (cl) |
381 | printk("%s/", cl->name); | 405 | pr_cont("%s/", cl->name); |
382 | else | 406 | else |
383 | printk("%02x/", st2); | 407 | pr_cont("%02x/", st2); |
384 | 408 | ||
385 | if (cl && cl->data) cl = nouveau_enum_find(cl->data, st3); | 409 | if (cl && cl->data) cl = nouveau_enum_find(cl->data, st3); |
386 | else if (en && en->data) cl = nouveau_enum_find(en->data, st3); | 410 | else if (en && en->data) cl = nouveau_enum_find(en->data, st3); |
387 | else cl = NULL; | 411 | else cl = NULL; |
388 | if (cl) | 412 | if (cl) |
389 | printk("%s", cl->name); | 413 | pr_cont("%s", cl->name); |
390 | else | 414 | else |
391 | printk("%02x", st3); | 415 | pr_cont("%02x", st3); |
392 | 416 | ||
393 | printk(" reason: "); | 417 | pr_cont(" reason: "); |
394 | en = nouveau_enum_find(vm_fault, st1); | 418 | en = nouveau_enum_find(vm_fault, st1); |
395 | if (en) | 419 | if (en) |
396 | printk("%s\n", en->name); | 420 | pr_cont("%s\n", en->name); |
397 | else | 421 | else |
398 | printk("0x%08x\n", st1); | 422 | pr_cont("0x%08x\n", st1); |
399 | } | 423 | } |
400 | 424 | ||
401 | static int | 425 | static int |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c index 9fb0f9b92d49..d422acc9af15 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c | |||
@@ -102,135 +102,19 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line) | |||
102 | return ret; | 102 | return ret; |
103 | } | 103 | } |
104 | 104 | ||
105 | static int | 105 | void |
106 | nouveau_gpio_irq(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, bool on) | 106 | _nouveau_gpio_dtor(struct nouveau_object *object) |
107 | { | ||
108 | struct dcb_gpio_func func; | ||
109 | int ret; | ||
110 | |||
111 | ret = nouveau_gpio_find(gpio, idx, tag, line, &func); | ||
112 | if (ret == 0) { | ||
113 | if (idx == 0 && gpio->irq_enable) | ||
114 | gpio->irq_enable(gpio, func.line, on); | ||
115 | else | ||
116 | ret = -ENODEV; | ||
117 | } | ||
118 | |||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | struct gpio_isr { | ||
123 | struct nouveau_gpio *gpio; | ||
124 | struct list_head head; | ||
125 | struct work_struct work; | ||
126 | int idx; | ||
127 | struct dcb_gpio_func func; | ||
128 | void (*handler)(void *, int); | ||
129 | void *data; | ||
130 | bool inhibit; | ||
131 | }; | ||
132 | |||
133 | static void | ||
134 | nouveau_gpio_isr_bh(struct work_struct *work) | ||
135 | { | ||
136 | struct gpio_isr *isr = container_of(work, struct gpio_isr, work); | ||
137 | struct nouveau_gpio *gpio = isr->gpio; | ||
138 | unsigned long flags; | ||
139 | int state; | ||
140 | |||
141 | state = nouveau_gpio_get(gpio, isr->idx, isr->func.func, | ||
142 | isr->func.line); | ||
143 | if (state >= 0) | ||
144 | isr->handler(isr->data, state); | ||
145 | |||
146 | spin_lock_irqsave(&gpio->lock, flags); | ||
147 | isr->inhibit = false; | ||
148 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
149 | } | ||
150 | |||
151 | static void | ||
152 | nouveau_gpio_isr_run(struct nouveau_gpio *gpio, int idx, u32 line_mask) | ||
153 | { | ||
154 | struct gpio_isr *isr; | ||
155 | |||
156 | if (idx != 0) | ||
157 | return; | ||
158 | |||
159 | spin_lock(&gpio->lock); | ||
160 | list_for_each_entry(isr, &gpio->isr, head) { | ||
161 | if (line_mask & (1 << isr->func.line)) { | ||
162 | if (isr->inhibit) | ||
163 | continue; | ||
164 | isr->inhibit = true; | ||
165 | schedule_work(&isr->work); | ||
166 | } | ||
167 | } | ||
168 | spin_unlock(&gpio->lock); | ||
169 | } | ||
170 | |||
171 | static int | ||
172 | nouveau_gpio_isr_add(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, | ||
173 | void (*handler)(void *, int), void *data) | ||
174 | { | ||
175 | struct gpio_isr *isr; | ||
176 | unsigned long flags; | ||
177 | int ret; | ||
178 | |||
179 | isr = kzalloc(sizeof(*isr), GFP_KERNEL); | ||
180 | if (!isr) | ||
181 | return -ENOMEM; | ||
182 | |||
183 | ret = nouveau_gpio_find(gpio, idx, tag, line, &isr->func); | ||
184 | if (ret) { | ||
185 | kfree(isr); | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | INIT_WORK(&isr->work, nouveau_gpio_isr_bh); | ||
190 | isr->gpio = gpio; | ||
191 | isr->handler = handler; | ||
192 | isr->data = data; | ||
193 | isr->idx = idx; | ||
194 | |||
195 | spin_lock_irqsave(&gpio->lock, flags); | ||
196 | list_add(&isr->head, &gpio->isr); | ||
197 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static void | ||
202 | nouveau_gpio_isr_del(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, | ||
203 | void (*handler)(void *, int), void *data) | ||
204 | { | 107 | { |
205 | struct gpio_isr *isr, *tmp; | 108 | struct nouveau_gpio *gpio = (void *)object; |
206 | struct dcb_gpio_func func; | 109 | nouveau_event_destroy(&gpio->events); |
207 | unsigned long flags; | 110 | nouveau_subdev_destroy(&gpio->base); |
208 | LIST_HEAD(tofree); | ||
209 | int ret; | ||
210 | |||
211 | ret = nouveau_gpio_find(gpio, idx, tag, line, &func); | ||
212 | if (ret == 0) { | ||
213 | spin_lock_irqsave(&gpio->lock, flags); | ||
214 | list_for_each_entry_safe(isr, tmp, &gpio->isr, head) { | ||
215 | if (memcmp(&isr->func, &func, sizeof(func)) || | ||
216 | isr->idx != idx || | ||
217 | isr->handler != handler || isr->data != data) | ||
218 | continue; | ||
219 | list_move_tail(&isr->head, &tofree); | ||
220 | } | ||
221 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
222 | |||
223 | list_for_each_entry_safe(isr, tmp, &tofree, head) { | ||
224 | flush_work(&isr->work); | ||
225 | kfree(isr); | ||
226 | } | ||
227 | } | ||
228 | } | 111 | } |
229 | 112 | ||
230 | int | 113 | int |
231 | nouveau_gpio_create_(struct nouveau_object *parent, | 114 | nouveau_gpio_create_(struct nouveau_object *parent, |
232 | struct nouveau_object *engine, | 115 | struct nouveau_object *engine, |
233 | struct nouveau_oclass *oclass, int length, void **pobject) | 116 | struct nouveau_oclass *oclass, int lines, |
117 | int length, void **pobject) | ||
234 | { | 118 | { |
235 | struct nouveau_gpio *gpio; | 119 | struct nouveau_gpio *gpio; |
236 | int ret; | 120 | int ret; |
@@ -241,15 +125,13 @@ nouveau_gpio_create_(struct nouveau_object *parent, | |||
241 | if (ret) | 125 | if (ret) |
242 | return ret; | 126 | return ret; |
243 | 127 | ||
128 | ret = nouveau_event_create(lines, &gpio->events); | ||
129 | if (ret) | ||
130 | return ret; | ||
131 | |||
244 | gpio->find = nouveau_gpio_find; | 132 | gpio->find = nouveau_gpio_find; |
245 | gpio->set = nouveau_gpio_set; | 133 | gpio->set = nouveau_gpio_set; |
246 | gpio->get = nouveau_gpio_get; | 134 | gpio->get = nouveau_gpio_get; |
247 | gpio->irq = nouveau_gpio_irq; | ||
248 | gpio->isr_run = nouveau_gpio_isr_run; | ||
249 | gpio->isr_add = nouveau_gpio_isr_add; | ||
250 | gpio->isr_del = nouveau_gpio_isr_del; | ||
251 | INIT_LIST_HEAD(&gpio->isr); | ||
252 | spin_lock_init(&gpio->lock); | ||
253 | return 0; | 135 | return 0; |
254 | } | 136 | } |
255 | 137 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c index 168d16a9a8e9..76d5d5465ddd 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c | |||
@@ -24,7 +24,7 @@ | |||
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <subdev/gpio.h> | 27 | #include "priv.h" |
28 | 28 | ||
29 | struct nv10_gpio_priv { | 29 | struct nv10_gpio_priv { |
30 | struct nouveau_gpio base; | 30 | struct nouveau_gpio base; |
@@ -83,27 +83,36 @@ nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) | |||
83 | } | 83 | } |
84 | 84 | ||
85 | static void | 85 | static void |
86 | nv10_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on) | ||
87 | { | ||
88 | u32 mask = 0x00010001 << line; | ||
89 | |||
90 | nv_wr32(gpio, 0x001104, mask); | ||
91 | nv_mask(gpio, 0x001144, mask, on ? mask : 0); | ||
92 | } | ||
93 | |||
94 | static void | ||
95 | nv10_gpio_intr(struct nouveau_subdev *subdev) | 86 | nv10_gpio_intr(struct nouveau_subdev *subdev) |
96 | { | 87 | { |
97 | struct nv10_gpio_priv *priv = (void *)subdev; | 88 | struct nv10_gpio_priv *priv = (void *)subdev; |
98 | u32 intr = nv_rd32(priv, 0x001104); | 89 | u32 intr = nv_rd32(priv, 0x001104); |
99 | u32 hi = (intr & 0x0000ffff) >> 0; | 90 | u32 hi = (intr & 0x0000ffff) >> 0; |
100 | u32 lo = (intr & 0xffff0000) >> 16; | 91 | u32 lo = (intr & 0xffff0000) >> 16; |
92 | int i; | ||
101 | 93 | ||
102 | priv->base.isr_run(&priv->base, 0, hi | lo); | 94 | for (i = 0; (hi | lo) && i < 32; i++) { |
95 | if ((hi | lo) & (1 << i)) | ||
96 | nouveau_event_trigger(priv->base.events, i); | ||
97 | } | ||
103 | 98 | ||
104 | nv_wr32(priv, 0x001104, intr); | 99 | nv_wr32(priv, 0x001104, intr); |
105 | } | 100 | } |
106 | 101 | ||
102 | static void | ||
103 | nv10_gpio_intr_enable(struct nouveau_event *event, int line) | ||
104 | { | ||
105 | nv_wr32(event->priv, 0x001104, 0x00010001 << line); | ||
106 | nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00010001 << line); | ||
107 | } | ||
108 | |||
109 | static void | ||
110 | nv10_gpio_intr_disable(struct nouveau_event *event, int line) | ||
111 | { | ||
112 | nv_wr32(event->priv, 0x001104, 0x00010001 << line); | ||
113 | nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00000000); | ||
114 | } | ||
115 | |||
107 | static int | 116 | static int |
108 | nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 117 | nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
109 | struct nouveau_oclass *oclass, void *data, u32 size, | 118 | struct nouveau_oclass *oclass, void *data, u32 size, |
@@ -112,14 +121,16 @@ nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
112 | struct nv10_gpio_priv *priv; | 121 | struct nv10_gpio_priv *priv; |
113 | int ret; | 122 | int ret; |
114 | 123 | ||
115 | ret = nouveau_gpio_create(parent, engine, oclass, &priv); | 124 | ret = nouveau_gpio_create(parent, engine, oclass, 16, &priv); |
116 | *pobject = nv_object(priv); | 125 | *pobject = nv_object(priv); |
117 | if (ret) | 126 | if (ret) |
118 | return ret; | 127 | return ret; |
119 | 128 | ||
120 | priv->base.drive = nv10_gpio_drive; | 129 | priv->base.drive = nv10_gpio_drive; |
121 | priv->base.sense = nv10_gpio_sense; | 130 | priv->base.sense = nv10_gpio_sense; |
122 | priv->base.irq_enable = nv10_gpio_irq_enable; | 131 | priv->base.events->priv = priv; |
132 | priv->base.events->enable = nv10_gpio_intr_enable; | ||
133 | priv->base.events->disable = nv10_gpio_intr_disable; | ||
123 | nv_subdev(priv)->intr = nv10_gpio_intr; | 134 | nv_subdev(priv)->intr = nv10_gpio_intr; |
124 | return 0; | 135 | return 0; |
125 | } | 136 | } |
@@ -141,8 +152,6 @@ nv10_gpio_init(struct nouveau_object *object) | |||
141 | if (ret) | 152 | if (ret) |
142 | return ret; | 153 | return ret; |
143 | 154 | ||
144 | nv_wr32(priv, 0x001140, 0x00000000); | ||
145 | nv_wr32(priv, 0x001100, 0xffffffff); | ||
146 | nv_wr32(priv, 0x001144, 0x00000000); | 155 | nv_wr32(priv, 0x001144, 0x00000000); |
147 | nv_wr32(priv, 0x001104, 0xffffffff); | 156 | nv_wr32(priv, 0x001104, 0xffffffff); |
148 | return 0; | 157 | return 0; |
@@ -152,7 +161,6 @@ static int | |||
152 | nv10_gpio_fini(struct nouveau_object *object, bool suspend) | 161 | nv10_gpio_fini(struct nouveau_object *object, bool suspend) |
153 | { | 162 | { |
154 | struct nv10_gpio_priv *priv = (void *)object; | 163 | struct nv10_gpio_priv *priv = (void *)object; |
155 | nv_wr32(priv, 0x001140, 0x00000000); | ||
156 | nv_wr32(priv, 0x001144, 0x00000000); | 164 | nv_wr32(priv, 0x001144, 0x00000000); |
157 | return nouveau_gpio_fini(&priv->base, suspend); | 165 | return nouveau_gpio_fini(&priv->base, suspend); |
158 | } | 166 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c index bf13a1200f26..bf489dcf46e2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <subdev/gpio.h> | 25 | #include "priv.h" |
26 | 26 | ||
27 | struct nv50_gpio_priv { | 27 | struct nv50_gpio_priv { |
28 | struct nouveau_gpio base; | 28 | struct nouveau_gpio base; |
@@ -95,21 +95,12 @@ nv50_gpio_sense(struct nouveau_gpio *gpio, int line) | |||
95 | } | 95 | } |
96 | 96 | ||
97 | void | 97 | void |
98 | nv50_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on) | ||
99 | { | ||
100 | u32 reg = line < 16 ? 0xe050 : 0xe070; | ||
101 | u32 mask = 0x00010001 << (line & 0xf); | ||
102 | |||
103 | nv_wr32(gpio, reg + 4, mask); | ||
104 | nv_mask(gpio, reg + 0, mask, on ? mask : 0); | ||
105 | } | ||
106 | |||
107 | void | ||
108 | nv50_gpio_intr(struct nouveau_subdev *subdev) | 98 | nv50_gpio_intr(struct nouveau_subdev *subdev) |
109 | { | 99 | { |
110 | struct nv50_gpio_priv *priv = (void *)subdev; | 100 | struct nv50_gpio_priv *priv = (void *)subdev; |
111 | u32 intr0, intr1 = 0; | 101 | u32 intr0, intr1 = 0; |
112 | u32 hi, lo; | 102 | u32 hi, lo; |
103 | int i; | ||
113 | 104 | ||
114 | intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050); | 105 | intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050); |
115 | if (nv_device(priv)->chipset >= 0x90) | 106 | if (nv_device(priv)->chipset >= 0x90) |
@@ -117,13 +108,35 @@ nv50_gpio_intr(struct nouveau_subdev *subdev) | |||
117 | 108 | ||
118 | hi = (intr0 & 0x0000ffff) | (intr1 << 16); | 109 | hi = (intr0 & 0x0000ffff) | (intr1 << 16); |
119 | lo = (intr0 >> 16) | (intr1 & 0xffff0000); | 110 | lo = (intr0 >> 16) | (intr1 & 0xffff0000); |
120 | priv->base.isr_run(&priv->base, 0, hi | lo); | 111 | |
112 | for (i = 0; (hi | lo) && i < 32; i++) { | ||
113 | if ((hi | lo) & (1 << i)) | ||
114 | nouveau_event_trigger(priv->base.events, i); | ||
115 | } | ||
121 | 116 | ||
122 | nv_wr32(priv, 0xe054, intr0); | 117 | nv_wr32(priv, 0xe054, intr0); |
123 | if (nv_device(priv)->chipset >= 0x90) | 118 | if (nv_device(priv)->chipset >= 0x90) |
124 | nv_wr32(priv, 0xe074, intr1); | 119 | nv_wr32(priv, 0xe074, intr1); |
125 | } | 120 | } |
126 | 121 | ||
122 | void | ||
123 | nv50_gpio_intr_enable(struct nouveau_event *event, int line) | ||
124 | { | ||
125 | const u32 addr = line < 16 ? 0xe050 : 0xe070; | ||
126 | const u32 mask = 0x00010001 << (line & 0xf); | ||
127 | nv_wr32(event->priv, addr + 0x04, mask); | ||
128 | nv_mask(event->priv, addr + 0x00, mask, mask); | ||
129 | } | ||
130 | |||
131 | void | ||
132 | nv50_gpio_intr_disable(struct nouveau_event *event, int line) | ||
133 | { | ||
134 | const u32 addr = line < 16 ? 0xe050 : 0xe070; | ||
135 | const u32 mask = 0x00010001 << (line & 0xf); | ||
136 | nv_wr32(event->priv, addr + 0x04, mask); | ||
137 | nv_mask(event->priv, addr + 0x00, mask, 0x00000000); | ||
138 | } | ||
139 | |||
127 | static int | 140 | static int |
128 | nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 141 | nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
129 | struct nouveau_oclass *oclass, void *data, u32 size, | 142 | struct nouveau_oclass *oclass, void *data, u32 size, |
@@ -132,7 +145,9 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
132 | struct nv50_gpio_priv *priv; | 145 | struct nv50_gpio_priv *priv; |
133 | int ret; | 146 | int ret; |
134 | 147 | ||
135 | ret = nouveau_gpio_create(parent, engine, oclass, &priv); | 148 | ret = nouveau_gpio_create(parent, engine, oclass, |
149 | nv_device(parent)->chipset >= 0x90 ? 32 : 16, | ||
150 | &priv); | ||
136 | *pobject = nv_object(priv); | 151 | *pobject = nv_object(priv); |
137 | if (ret) | 152 | if (ret) |
138 | return ret; | 153 | return ret; |
@@ -140,7 +155,9 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
140 | priv->base.reset = nv50_gpio_reset; | 155 | priv->base.reset = nv50_gpio_reset; |
141 | priv->base.drive = nv50_gpio_drive; | 156 | priv->base.drive = nv50_gpio_drive; |
142 | priv->base.sense = nv50_gpio_sense; | 157 | priv->base.sense = nv50_gpio_sense; |
143 | priv->base.irq_enable = nv50_gpio_irq_enable; | 158 | priv->base.events->priv = priv; |
159 | priv->base.events->enable = nv50_gpio_intr_enable; | ||
160 | priv->base.events->disable = nv50_gpio_intr_disable; | ||
144 | nv_subdev(priv)->intr = nv50_gpio_intr; | 161 | nv_subdev(priv)->intr = nv50_gpio_intr; |
145 | return 0; | 162 | return 0; |
146 | } | 163 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c index 83e8b8f16e6a..010431e3acec 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c | |||
@@ -22,13 +22,13 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <subdev/gpio.h> | 25 | #include "priv.h" |
26 | 26 | ||
27 | struct nvd0_gpio_priv { | 27 | struct nvd0_gpio_priv { |
28 | struct nouveau_gpio base; | 28 | struct nouveau_gpio base; |
29 | }; | 29 | }; |
30 | 30 | ||
31 | static void | 31 | void |
32 | nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match) | 32 | nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match) |
33 | { | 33 | { |
34 | struct nouveau_bios *bios = nouveau_bios(gpio); | 34 | struct nouveau_bios *bios = nouveau_bios(gpio); |
@@ -57,7 +57,7 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match) | |||
57 | } | 57 | } |
58 | } | 58 | } |
59 | 59 | ||
60 | static int | 60 | int |
61 | nvd0_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) | 61 | nvd0_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) |
62 | { | 62 | { |
63 | u32 data = ((dir ^ 1) << 13) | (out << 12); | 63 | u32 data = ((dir ^ 1) << 13) | (out << 12); |
@@ -66,7 +66,7 @@ nvd0_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) | |||
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | 68 | ||
69 | static int | 69 | int |
70 | nvd0_gpio_sense(struct nouveau_gpio *gpio, int line) | 70 | nvd0_gpio_sense(struct nouveau_gpio *gpio, int line) |
71 | { | 71 | { |
72 | return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000); | 72 | return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000); |
@@ -80,7 +80,7 @@ nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
80 | struct nvd0_gpio_priv *priv; | 80 | struct nvd0_gpio_priv *priv; |
81 | int ret; | 81 | int ret; |
82 | 82 | ||
83 | ret = nouveau_gpio_create(parent, engine, oclass, &priv); | 83 | ret = nouveau_gpio_create(parent, engine, oclass, 32, &priv); |
84 | *pobject = nv_object(priv); | 84 | *pobject = nv_object(priv); |
85 | if (ret) | 85 | if (ret) |
86 | return ret; | 86 | return ret; |
@@ -88,7 +88,9 @@ nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
88 | priv->base.reset = nvd0_gpio_reset; | 88 | priv->base.reset = nvd0_gpio_reset; |
89 | priv->base.drive = nvd0_gpio_drive; | 89 | priv->base.drive = nvd0_gpio_drive; |
90 | priv->base.sense = nvd0_gpio_sense; | 90 | priv->base.sense = nvd0_gpio_sense; |
91 | priv->base.irq_enable = nv50_gpio_irq_enable; | 91 | priv->base.events->priv = priv; |
92 | priv->base.events->enable = nv50_gpio_intr_enable; | ||
93 | priv->base.events->disable = nv50_gpio_intr_disable; | ||
92 | nv_subdev(priv)->intr = nv50_gpio_intr; | 94 | nv_subdev(priv)->intr = nv50_gpio_intr; |
93 | return 0; | 95 | return 0; |
94 | } | 96 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c new file mode 100644 index 000000000000..16b8c5bf5efa --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c | |||
@@ -0,0 +1,131 @@ | |||
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 | struct nve0_gpio_priv { | ||
28 | struct nouveau_gpio base; | ||
29 | }; | ||
30 | |||
31 | void | ||
32 | nve0_gpio_intr(struct nouveau_subdev *subdev) | ||
33 | { | ||
34 | struct nve0_gpio_priv *priv = (void *)subdev; | ||
35 | u32 intr0 = nv_rd32(priv, 0xdc00) & nv_rd32(priv, 0xdc08); | ||
36 | u32 intr1 = nv_rd32(priv, 0xdc80) & nv_rd32(priv, 0xdc88); | ||
37 | u32 hi = (intr0 & 0x0000ffff) | (intr1 << 16); | ||
38 | u32 lo = (intr0 >> 16) | (intr1 & 0xffff0000); | ||
39 | int i; | ||
40 | |||
41 | for (i = 0; (hi | lo) && i < 32; i++) { | ||
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, 0xdc88, intr1); | ||
48 | } | ||
49 | |||
50 | void | ||
51 | nve0_gpio_intr_enable(struct nouveau_event *event, int line) | ||
52 | { | ||
53 | const u32 addr = line < 16 ? 0xdc00 : 0xdc80; | ||
54 | const u32 mask = 0x00010001 << (line & 0xf); | ||
55 | nv_wr32(event->priv, addr + 0x08, mask); | ||
56 | nv_mask(event->priv, addr + 0x00, mask, mask); | ||
57 | } | ||
58 | |||
59 | void | ||
60 | nve0_gpio_intr_disable(struct nouveau_event *event, int line) | ||
61 | { | ||
62 | const u32 addr = line < 16 ? 0xdc00 : 0xdc80; | ||
63 | const u32 mask = 0x00010001 << (line & 0xf); | ||
64 | nv_wr32(event->priv, addr + 0x08, mask); | ||
65 | nv_mask(event->priv, addr + 0x00, mask, 0x00000000); | ||
66 | } | ||
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 | } | ||
121 | |||
122 | struct nouveau_oclass | ||
123 | nve0_gpio_oclass = { | ||
124 | .handle = NV_SUBDEV(GPIO, 0xe0), | ||
125 | .ofuncs = &(struct nouveau_ofuncs) { | ||
126 | .ctor = nve0_gpio_ctor, | ||
127 | .dtor = nv50_gpio_dtor, | ||
128 | .init = nve0_gpio_init, | ||
129 | .fini = nve0_gpio_fini, | ||
130 | }, | ||
131 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h new file mode 100644 index 000000000000..2ee1c895c782 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef __NVKM_GPIO_H__ | ||
2 | #define __NVKM_GPIO_H__ | ||
3 | |||
4 | #include <subdev/gpio.h> | ||
5 | |||
6 | void nv50_gpio_dtor(struct nouveau_object *); | ||
7 | int nv50_gpio_init(struct nouveau_object *); | ||
8 | int nv50_gpio_fini(struct nouveau_object *, bool); | ||
9 | void nv50_gpio_intr(struct nouveau_subdev *); | ||
10 | void nv50_gpio_intr_enable(struct nouveau_event *, int line); | ||
11 | void nv50_gpio_intr_disable(struct nouveau_event *, int line); | ||
12 | |||
13 | void nvd0_gpio_reset(struct nouveau_gpio *, u8); | ||
14 | int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int); | ||
15 | int nvd0_gpio_sense(struct nouveau_gpio *, int); | ||
16 | |||
17 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c new file mode 100644 index 000000000000..dec94e9d776a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | * Copyright 2013 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 <bskeggs@redhat.com> | ||
23 | */ | ||
24 | |||
25 | #include <subdev/i2c.h> | ||
26 | |||
27 | struct anx9805_i2c_port { | ||
28 | struct nouveau_i2c_port base; | ||
29 | u32 addr; | ||
30 | u32 ctrl; | ||
31 | }; | ||
32 | |||
33 | static int | ||
34 | anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh) | ||
35 | { | ||
36 | struct anx9805_i2c_port *chan = (void *)port; | ||
37 | struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; | ||
38 | u8 tmp, i; | ||
39 | |||
40 | nv_wri2cr(mast, chan->addr, 0xa0, link_bw); | ||
41 | nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); | ||
42 | nv_wri2cr(mast, chan->addr, 0xa2, 0x01); | ||
43 | nv_wri2cr(mast, chan->addr, 0xa8, 0x01); | ||
44 | |||
45 | i = 0; | ||
46 | while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) { | ||
47 | mdelay(5); | ||
48 | if (i++ == 100) { | ||
49 | nv_error(port, "link training timed out\n"); | ||
50 | return -ETIMEDOUT; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | if (tmp & 0x70) { | ||
55 | nv_error(port, "link training failed: 0x%02x\n", tmp); | ||
56 | return -EIO; | ||
57 | } | ||
58 | |||
59 | return 1; | ||
60 | } | ||
61 | |||
62 | static int | ||
63 | anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size) | ||
64 | { | ||
65 | struct anx9805_i2c_port *chan = (void *)port; | ||
66 | struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; | ||
67 | int i, ret = -ETIMEDOUT; | ||
68 | u8 tmp; | ||
69 | |||
70 | tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04; | ||
71 | nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04); | ||
72 | nv_wri2cr(mast, chan->ctrl, 0x07, tmp); | ||
73 | nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); | ||
74 | |||
75 | nv_wri2cr(mast, chan->addr, 0xe4, 0x80); | ||
76 | for (i = 0; !(type & 1) && i < size; i++) | ||
77 | nv_wri2cr(mast, chan->addr, 0xf0 + i, data[i]); | ||
78 | nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type); | ||
79 | nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0); | ||
80 | nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8); | ||
81 | nv_wri2cr(mast, chan->addr, 0xe8, (addr & 0xf0000) >> 16); | ||
82 | nv_wri2cr(mast, chan->addr, 0xe9, 0x01); | ||
83 | |||
84 | i = 0; | ||
85 | while ((tmp = nv_rdi2cr(mast, chan->addr, 0xe9)) & 0x01) { | ||
86 | mdelay(5); | ||
87 | if (i++ == 32) | ||
88 | goto done; | ||
89 | } | ||
90 | |||
91 | if ((tmp = nv_rdi2cr(mast, chan->ctrl, 0xf7)) & 0x01) { | ||
92 | ret = -EIO; | ||
93 | goto done; | ||
94 | } | ||
95 | |||
96 | for (i = 0; (type & 1) && i < size; i++) | ||
97 | data[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i); | ||
98 | ret = 0; | ||
99 | done: | ||
100 | nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | static const struct nouveau_i2c_func | ||
105 | anx9805_aux_func = { | ||
106 | .aux = anx9805_aux, | ||
107 | .lnk_ctl = anx9805_train, | ||
108 | }; | ||
109 | |||
110 | static int | ||
111 | anx9805_aux_chan_ctor(struct nouveau_object *parent, | ||
112 | struct nouveau_object *engine, | ||
113 | struct nouveau_oclass *oclass, void *data, u32 index, | ||
114 | struct nouveau_object **pobject) | ||
115 | { | ||
116 | struct nouveau_i2c_port *mast = (void *)parent; | ||
117 | struct anx9805_i2c_port *chan; | ||
118 | int ret; | ||
119 | |||
120 | ret = nouveau_i2c_port_create(parent, engine, oclass, index, | ||
121 | &nouveau_i2c_aux_algo, &chan); | ||
122 | *pobject = nv_object(chan); | ||
123 | if (ret) | ||
124 | return ret; | ||
125 | |||
126 | switch ((oclass->handle & 0xff00) >> 8) { | ||
127 | case 0x0d: | ||
128 | chan->addr = 0x38; | ||
129 | chan->ctrl = 0x39; | ||
130 | break; | ||
131 | case 0x0e: | ||
132 | chan->addr = 0x3c; | ||
133 | chan->ctrl = 0x3b; | ||
134 | break; | ||
135 | default: | ||
136 | BUG_ON(1); | ||
137 | } | ||
138 | |||
139 | if (mast->adapter.algo == &i2c_bit_algo) { | ||
140 | struct i2c_algo_bit_data *algo = mast->adapter.algo_data; | ||
141 | algo->udelay = max(algo->udelay, 40); | ||
142 | } | ||
143 | |||
144 | chan->base.func = &anx9805_aux_func; | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static struct nouveau_ofuncs | ||
149 | anx9805_aux_ofuncs = { | ||
150 | .ctor = anx9805_aux_chan_ctor, | ||
151 | .dtor = _nouveau_i2c_port_dtor, | ||
152 | .init = _nouveau_i2c_port_init, | ||
153 | .fini = _nouveau_i2c_port_fini, | ||
154 | }; | ||
155 | |||
156 | static int | ||
157 | anx9805_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | ||
158 | { | ||
159 | struct anx9805_i2c_port *port = adap->algo_data; | ||
160 | struct nouveau_i2c_port *mast = (void *)nv_object(port)->parent; | ||
161 | struct i2c_msg *msg = msgs; | ||
162 | int ret = -ETIMEDOUT; | ||
163 | int i, j, cnt = num; | ||
164 | u8 seg = 0x00, off = 0x00, tmp; | ||
165 | |||
166 | tmp = nv_rdi2cr(mast, port->ctrl, 0x07) & ~0x10; | ||
167 | nv_wri2cr(mast, port->ctrl, 0x07, tmp | 0x10); | ||
168 | nv_wri2cr(mast, port->ctrl, 0x07, tmp); | ||
169 | nv_wri2cr(mast, port->addr, 0x43, 0x05); | ||
170 | mdelay(5); | ||
171 | |||
172 | while (cnt--) { | ||
173 | if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) { | ||
174 | nv_wri2cr(mast, port->addr, 0x40, msg->addr << 1); | ||
175 | nv_wri2cr(mast, port->addr, 0x41, seg); | ||
176 | nv_wri2cr(mast, port->addr, 0x42, off); | ||
177 | nv_wri2cr(mast, port->addr, 0x44, msg->len); | ||
178 | nv_wri2cr(mast, port->addr, 0x45, 0x00); | ||
179 | nv_wri2cr(mast, port->addr, 0x43, 0x01); | ||
180 | for (i = 0; i < msg->len; i++) { | ||
181 | j = 0; | ||
182 | while (nv_rdi2cr(mast, port->addr, 0x46) & 0x10) { | ||
183 | mdelay(5); | ||
184 | if (j++ == 32) | ||
185 | goto done; | ||
186 | } | ||
187 | msg->buf[i] = nv_rdi2cr(mast, port->addr, 0x47); | ||
188 | } | ||
189 | } else | ||
190 | if (!(msg->flags & I2C_M_RD)) { | ||
191 | if (msg->addr == 0x50 && msg->len == 0x01) { | ||
192 | off = msg->buf[0]; | ||
193 | } else | ||
194 | if (msg->addr == 0x30 && msg->len == 0x01) { | ||
195 | seg = msg->buf[0]; | ||
196 | } else | ||
197 | goto done; | ||
198 | } else { | ||
199 | goto done; | ||
200 | } | ||
201 | msg++; | ||
202 | } | ||
203 | |||
204 | ret = num; | ||
205 | done: | ||
206 | nv_wri2cr(mast, port->addr, 0x43, 0x00); | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | static u32 | ||
211 | anx9805_func(struct i2c_adapter *adap) | ||
212 | { | ||
213 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
214 | } | ||
215 | |||
216 | static const struct i2c_algorithm | ||
217 | anx9805_i2c_algo = { | ||
218 | .master_xfer = anx9805_xfer, | ||
219 | .functionality = anx9805_func | ||
220 | }; | ||
221 | |||
222 | static const struct nouveau_i2c_func | ||
223 | anx9805_i2c_func = { | ||
224 | }; | ||
225 | |||
226 | static int | ||
227 | anx9805_ddc_port_ctor(struct nouveau_object *parent, | ||
228 | struct nouveau_object *engine, | ||
229 | struct nouveau_oclass *oclass, void *data, u32 index, | ||
230 | struct nouveau_object **pobject) | ||
231 | { | ||
232 | struct nouveau_i2c_port *mast = (void *)parent; | ||
233 | struct anx9805_i2c_port *port; | ||
234 | int ret; | ||
235 | |||
236 | ret = nouveau_i2c_port_create(parent, engine, oclass, index, | ||
237 | &anx9805_i2c_algo, &port); | ||
238 | *pobject = nv_object(port); | ||
239 | if (ret) | ||
240 | return ret; | ||
241 | |||
242 | switch ((oclass->handle & 0xff00) >> 8) { | ||
243 | case 0x0d: | ||
244 | port->addr = 0x3d; | ||
245 | port->ctrl = 0x39; | ||
246 | break; | ||
247 | case 0x0e: | ||
248 | port->addr = 0x3f; | ||
249 | port->ctrl = 0x3b; | ||
250 | break; | ||
251 | default: | ||
252 | BUG_ON(1); | ||
253 | } | ||
254 | |||
255 | if (mast->adapter.algo == &i2c_bit_algo) { | ||
256 | struct i2c_algo_bit_data *algo = mast->adapter.algo_data; | ||
257 | algo->udelay = max(algo->udelay, 40); | ||
258 | } | ||
259 | |||
260 | port->base.func = &anx9805_i2c_func; | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static struct nouveau_ofuncs | ||
265 | anx9805_ddc_ofuncs = { | ||
266 | .ctor = anx9805_ddc_port_ctor, | ||
267 | .dtor = _nouveau_i2c_port_dtor, | ||
268 | .init = _nouveau_i2c_port_init, | ||
269 | .fini = _nouveau_i2c_port_fini, | ||
270 | }; | ||
271 | |||
272 | struct nouveau_oclass | ||
273 | nouveau_anx9805_sclass[] = { | ||
274 | { .handle = NV_I2C_TYPE_EXTDDC(0x0d), .ofuncs = &anx9805_ddc_ofuncs }, | ||
275 | { .handle = NV_I2C_TYPE_EXTAUX(0x0d), .ofuncs = &anx9805_aux_ofuncs }, | ||
276 | { .handle = NV_I2C_TYPE_EXTDDC(0x0e), .ofuncs = &anx9805_ddc_ofuncs }, | ||
277 | { .handle = NV_I2C_TYPE_EXTAUX(0x0e), .ofuncs = &anx9805_aux_ofuncs }, | ||
278 | {} | ||
279 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c index dc27e794a851..5de074ad170b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c | |||
@@ -24,151 +24,40 @@ | |||
24 | 24 | ||
25 | #include <subdev/i2c.h> | 25 | #include <subdev/i2c.h> |
26 | 26 | ||
27 | /****************************************************************************** | ||
28 | * aux channel util functions | ||
29 | *****************************************************************************/ | ||
30 | #define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args) | ||
31 | #define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args) | ||
32 | |||
33 | static void | ||
34 | auxch_fini(struct nouveau_i2c *aux, int ch) | ||
35 | { | ||
36 | nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); | ||
37 | } | ||
38 | |||
39 | static int | ||
40 | auxch_init(struct nouveau_i2c *aux, int ch) | ||
41 | { | ||
42 | const u32 unksel = 1; /* nfi which to use, or if it matters.. */ | ||
43 | const u32 ureq = unksel ? 0x00100000 : 0x00200000; | ||
44 | const u32 urep = unksel ? 0x01000000 : 0x02000000; | ||
45 | u32 ctrl, timeout; | ||
46 | |||
47 | /* wait up to 1ms for any previous transaction to be done... */ | ||
48 | timeout = 1000; | ||
49 | do { | ||
50 | ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); | ||
51 | udelay(1); | ||
52 | if (!timeout--) { | ||
53 | AUX_ERR("begin idle timeout 0x%08x\n", ctrl); | ||
54 | return -EBUSY; | ||
55 | } | ||
56 | } while (ctrl & 0x03010000); | ||
57 | |||
58 | /* set some magic, and wait up to 1ms for it to appear */ | ||
59 | nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); | ||
60 | timeout = 1000; | ||
61 | do { | ||
62 | ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); | ||
63 | udelay(1); | ||
64 | if (!timeout--) { | ||
65 | AUX_ERR("magic wait 0x%08x\n", ctrl); | ||
66 | auxch_fini(aux, ch); | ||
67 | return -EBUSY; | ||
68 | } | ||
69 | } while ((ctrl & 0x03000000) != urep); | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static int | ||
75 | auxch_tx(struct nouveau_i2c *aux, int ch, u8 type, u32 addr, u8 *data, u8 size) | ||
76 | { | ||
77 | u32 ctrl, stat, timeout, retries; | ||
78 | u32 xbuf[4] = {}; | ||
79 | int ret, i; | ||
80 | |||
81 | AUX_DBG("%d: 0x%08x %d\n", type, addr, size); | ||
82 | |||
83 | ret = auxch_init(aux, ch); | ||
84 | if (ret) | ||
85 | goto out; | ||
86 | |||
87 | stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50)); | ||
88 | if (!(stat & 0x10000000)) { | ||
89 | AUX_DBG("sink not detected\n"); | ||
90 | ret = -ENXIO; | ||
91 | goto out; | ||
92 | } | ||
93 | |||
94 | if (!(type & 1)) { | ||
95 | memcpy(xbuf, data, size); | ||
96 | for (i = 0; i < 16; i += 4) { | ||
97 | AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); | ||
98 | nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); | ||
103 | ctrl &= ~0x0001f0ff; | ||
104 | ctrl |= type << 12; | ||
105 | ctrl |= size - 1; | ||
106 | nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr); | ||
107 | |||
108 | /* retry transaction a number of times on failure... */ | ||
109 | ret = -EREMOTEIO; | ||
110 | for (retries = 0; retries < 32; retries++) { | ||
111 | /* reset, and delay a while if this is a retry */ | ||
112 | nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); | ||
113 | nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); | ||
114 | if (retries) | ||
115 | udelay(400); | ||
116 | |||
117 | /* transaction request, wait up to 1ms for it to complete */ | ||
118 | nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); | ||
119 | |||
120 | timeout = 1000; | ||
121 | do { | ||
122 | ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); | ||
123 | udelay(1); | ||
124 | if (!timeout--) { | ||
125 | AUX_ERR("tx req timeout 0x%08x\n", ctrl); | ||
126 | goto out; | ||
127 | } | ||
128 | } while (ctrl & 0x00010000); | ||
129 | |||
130 | /* read status, and check if transaction completed ok */ | ||
131 | stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0); | ||
132 | if (!(stat & 0x000f0f00)) { | ||
133 | ret = 0; | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); | ||
138 | } | ||
139 | |||
140 | if (type & 1) { | ||
141 | for (i = 0; i < 16; i += 4) { | ||
142 | xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i); | ||
143 | AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); | ||
144 | } | ||
145 | memcpy(data, xbuf, size); | ||
146 | } | ||
147 | |||
148 | out: | ||
149 | auxch_fini(aux, ch); | ||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | int | 27 | int |
154 | nv_rdaux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size) | 28 | nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) |
155 | { | 29 | { |
156 | return auxch_tx(auxch->i2c, auxch->drive, 9, addr, data, size); | 30 | if (port->func->aux) { |
31 | if (port->func->acquire) | ||
32 | port->func->acquire(port); | ||
33 | return port->func->aux(port, 9, addr, data, size); | ||
34 | } | ||
35 | return -ENODEV; | ||
157 | } | 36 | } |
158 | 37 | ||
159 | int | 38 | int |
160 | nv_wraux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size) | 39 | nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) |
161 | { | 40 | { |
162 | return auxch_tx(auxch->i2c, auxch->drive, 8, addr, data, size); | 41 | if (port->func->aux) { |
42 | if (port->func->acquire) | ||
43 | port->func->acquire(port); | ||
44 | return port->func->aux(port, 8, addr, data, size); | ||
45 | } | ||
46 | return -ENODEV; | ||
163 | } | 47 | } |
164 | 48 | ||
165 | static int | 49 | static int |
166 | aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | 50 | aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) |
167 | { | 51 | { |
168 | struct nouveau_i2c_port *auxch = (struct nouveau_i2c_port *)adap; | 52 | struct nouveau_i2c_port *port = adap->algo_data; |
169 | struct i2c_msg *msg = msgs; | 53 | struct i2c_msg *msg = msgs; |
170 | int ret, mcnt = num; | 54 | int ret, mcnt = num; |
171 | 55 | ||
56 | if (!port->func->aux) | ||
57 | return -ENODEV; | ||
58 | if ( port->func->acquire) | ||
59 | port->func->acquire(port); | ||
60 | |||
172 | while (mcnt--) { | 61 | while (mcnt--) { |
173 | u8 remaining = msg->len; | 62 | u8 remaining = msg->len; |
174 | u8 *ptr = msg->buf; | 63 | u8 *ptr = msg->buf; |
@@ -185,8 +74,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |||
185 | if (mcnt || remaining > 16) | 74 | if (mcnt || remaining > 16) |
186 | cmd |= 4; /* MOT */ | 75 | cmd |= 4; /* MOT */ |
187 | 76 | ||
188 | ret = auxch_tx(auxch->i2c, auxch->drive, cmd, | 77 | ret = port->func->aux(port, cmd, msg->addr, ptr, cnt); |
189 | msg->addr, ptr, cnt); | ||
190 | if (ret < 0) | 78 | if (ret < 0) |
191 | return ret; | 79 | return ret; |
192 | 80 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c index dbfc2abf0cfe..a114a0ed7e98 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2012 Red Hat Inc. | 2 | * Copyright 2013 Red Hat Inc. |
3 | * | 3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), | 5 | * copy of this software and associated documentation files (the "Software"), |
@@ -22,64 +22,136 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "core/option.h" | 25 | #include <core/option.h> |
26 | 26 | ||
27 | #include "subdev/i2c.h" | 27 | #include <subdev/bios.h> |
28 | #include "subdev/vga.h" | 28 | #include <subdev/bios/dcb.h> |
29 | #include <subdev/bios/i2c.h> | ||
30 | #include <subdev/i2c.h> | ||
31 | #include <subdev/vga.h> | ||
29 | 32 | ||
30 | int | 33 | /****************************************************************************** |
31 | nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg) | 34 | * interface to linux i2c bit-banging algorithm |
35 | *****************************************************************************/ | ||
36 | |||
37 | #ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT | ||
38 | #define CSTMSEL true | ||
39 | #else | ||
40 | #define CSTMSEL false | ||
41 | #endif | ||
42 | |||
43 | static int | ||
44 | nouveau_i2c_pre_xfer(struct i2c_adapter *adap) | ||
32 | { | 45 | { |
33 | u8 val; | 46 | struct i2c_algo_bit_data *bit = adap->algo_data; |
34 | struct i2c_msg msgs[] = { | 47 | struct nouveau_i2c_port *port = bit->data; |
35 | { .addr = addr, .flags = 0, .len = 1, .buf = ® }, | 48 | if (port->func->acquire) |
36 | { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val }, | 49 | port->func->acquire(port); |
37 | }; | 50 | return 0; |
51 | } | ||
38 | 52 | ||
39 | int ret = i2c_transfer(&port->adapter, msgs, 2); | 53 | static void |
40 | if (ret != 2) | 54 | nouveau_i2c_setscl(void *data, int state) |
41 | return -EIO; | 55 | { |
56 | struct nouveau_i2c_port *port = data; | ||
57 | port->func->drive_scl(port, state); | ||
58 | } | ||
42 | 59 | ||
43 | return val; | 60 | static void |
61 | nouveau_i2c_setsda(void *data, int state) | ||
62 | { | ||
63 | struct nouveau_i2c_port *port = data; | ||
64 | port->func->drive_sda(port, state); | ||
44 | } | 65 | } |
45 | 66 | ||
46 | int | 67 | static int |
47 | nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val) | 68 | nouveau_i2c_getscl(void *data) |
48 | { | 69 | { |
49 | struct i2c_msg msgs[] = { | 70 | struct nouveau_i2c_port *port = data; |
50 | { .addr = addr, .flags = 0, .len = 1, .buf = ® }, | 71 | return port->func->sense_scl(port); |
51 | { .addr = addr, .flags = 0, .len = 1, .buf = &val }, | 72 | } |
52 | }; | ||
53 | 73 | ||
54 | int ret = i2c_transfer(&port->adapter, msgs, 2); | 74 | static int |
55 | if (ret != 2) | 75 | nouveau_i2c_getsda(void *data) |
56 | return -EIO; | 76 | { |
77 | struct nouveau_i2c_port *port = data; | ||
78 | return port->func->sense_sda(port); | ||
79 | } | ||
57 | 80 | ||
58 | return 0; | 81 | /****************************************************************************** |
82 | * base i2c "port" class implementation | ||
83 | *****************************************************************************/ | ||
84 | |||
85 | void | ||
86 | _nouveau_i2c_port_dtor(struct nouveau_object *object) | ||
87 | { | ||
88 | struct nouveau_i2c_port *port = (void *)object; | ||
89 | i2c_del_adapter(&port->adapter); | ||
90 | nouveau_object_destroy(&port->base); | ||
59 | } | 91 | } |
60 | 92 | ||
61 | bool | 93 | int |
62 | nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr) | 94 | nouveau_i2c_port_create_(struct nouveau_object *parent, |
95 | struct nouveau_object *engine, | ||
96 | struct nouveau_oclass *oclass, u8 index, | ||
97 | const struct i2c_algorithm *algo, | ||
98 | int size, void **pobject) | ||
63 | { | 99 | { |
64 | u8 buf[] = { 0 }; | 100 | struct nouveau_device *device = nv_device(parent); |
65 | struct i2c_msg msgs[] = { | 101 | struct nouveau_i2c *i2c = (void *)engine; |
66 | { | 102 | struct nouveau_i2c_port *port; |
67 | .addr = addr, | 103 | int ret; |
68 | .flags = 0, | ||
69 | .len = 1, | ||
70 | .buf = buf, | ||
71 | }, | ||
72 | { | ||
73 | .addr = addr, | ||
74 | .flags = I2C_M_RD, | ||
75 | .len = 1, | ||
76 | .buf = buf, | ||
77 | } | ||
78 | }; | ||
79 | 104 | ||
80 | return i2c_transfer(&port->adapter, msgs, 2) == 2; | 105 | ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject); |
106 | port = *pobject; | ||
107 | if (ret) | ||
108 | return ret; | ||
109 | |||
110 | snprintf(port->adapter.name, sizeof(port->adapter.name), | ||
111 | "nouveau-%s-%d", device->name, index); | ||
112 | port->adapter.owner = THIS_MODULE; | ||
113 | port->adapter.dev.parent = &device->pdev->dev; | ||
114 | port->index = index; | ||
115 | i2c_set_adapdata(&port->adapter, i2c); | ||
116 | |||
117 | if ( algo == &nouveau_i2c_bit_algo && | ||
118 | !nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) { | ||
119 | struct i2c_algo_bit_data *bit; | ||
120 | |||
121 | bit = kzalloc(sizeof(*bit), GFP_KERNEL); | ||
122 | if (!bit) | ||
123 | return -ENOMEM; | ||
124 | |||
125 | bit->udelay = 10; | ||
126 | bit->timeout = usecs_to_jiffies(2200); | ||
127 | bit->data = port; | ||
128 | bit->pre_xfer = nouveau_i2c_pre_xfer; | ||
129 | bit->setsda = nouveau_i2c_setsda; | ||
130 | bit->setscl = nouveau_i2c_setscl; | ||
131 | bit->getsda = nouveau_i2c_getsda; | ||
132 | bit->getscl = nouveau_i2c_getscl; | ||
133 | |||
134 | port->adapter.algo_data = bit; | ||
135 | ret = i2c_bit_add_bus(&port->adapter); | ||
136 | } else { | ||
137 | port->adapter.algo_data = port; | ||
138 | port->adapter.algo = algo; | ||
139 | ret = i2c_add_adapter(&port->adapter); | ||
140 | } | ||
141 | |||
142 | /* drop port's i2c subdev refcount, i2c handles this itself */ | ||
143 | if (ret == 0) { | ||
144 | list_add_tail(&port->head, &i2c->ports); | ||
145 | atomic_dec(&engine->refcount); | ||
146 | } | ||
147 | |||
148 | return ret; | ||
81 | } | 149 | } |
82 | 150 | ||
151 | /****************************************************************************** | ||
152 | * base i2c subdev class implementation | ||
153 | *****************************************************************************/ | ||
154 | |||
83 | static struct nouveau_i2c_port * | 155 | static struct nouveau_i2c_port * |
84 | nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index) | 156 | nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index) |
85 | { | 157 | { |
@@ -103,29 +175,23 @@ nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index) | |||
103 | 175 | ||
104 | list_for_each_entry(port, &i2c->ports, head) { | 176 | list_for_each_entry(port, &i2c->ports, head) { |
105 | if (port->index == index) | 177 | if (port->index == index) |
106 | break; | 178 | return port; |
107 | } | 179 | } |
108 | 180 | ||
109 | if (&port->head == &i2c->ports) | 181 | return NULL; |
110 | return NULL; | 182 | } |
111 | 183 | ||
112 | if (nv_device(i2c)->card_type >= NV_50 && (port->dcb & 0x00000100)) { | 184 | static struct nouveau_i2c_port * |
113 | u32 reg = 0x00e500, val; | 185 | nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type) |
114 | if (port->type == 6) { | 186 | { |
115 | reg += port->drive * 0x50; | 187 | struct nouveau_i2c_port *port; |
116 | val = 0x2002; | ||
117 | } else { | ||
118 | reg += ((port->dcb & 0x1e00) >> 9) * 0x50; | ||
119 | val = 0xe001; | ||
120 | } | ||
121 | 188 | ||
122 | /* nfi, but neither auxch or i2c work if it's 1 */ | 189 | list_for_each_entry(port, &i2c->ports, head) { |
123 | nv_mask(i2c, reg + 0x0c, 0x00000001, 0x00000000); | 190 | if (nv_hclass(port) == type) |
124 | /* nfi, but switches auxch vs normal i2c */ | 191 | return port; |
125 | nv_mask(i2c, reg + 0x00, 0x0000f003, val); | ||
126 | } | 192 | } |
127 | 193 | ||
128 | return port; | 194 | return NULL; |
129 | } | 195 | } |
130 | 196 | ||
131 | static int | 197 | static int |
@@ -155,109 +221,86 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, | |||
155 | return -ENODEV; | 221 | return -ENODEV; |
156 | } | 222 | } |
157 | 223 | ||
158 | void | 224 | int |
159 | nouveau_i2c_drive_scl(void *data, int state) | 225 | _nouveau_i2c_fini(struct nouveau_object *object, bool suspend) |
160 | { | 226 | { |
161 | struct nouveau_i2c_port *port = data; | 227 | struct nouveau_i2c *i2c = (void *)object; |
228 | struct nouveau_i2c_port *port; | ||
229 | int ret; | ||
162 | 230 | ||
163 | if (port->type == DCB_I2C_NV04_BIT) { | 231 | list_for_each_entry(port, &i2c->ports, head) { |
164 | u8 val = nv_rdvgac(port->i2c, 0, port->drive); | 232 | ret = nv_ofuncs(port)->fini(nv_object(port), suspend); |
165 | if (state) val |= 0x20; | 233 | if (ret && suspend) |
166 | else val &= 0xdf; | 234 | goto fail; |
167 | nv_wrvgac(port->i2c, 0, port->drive, val | 0x01); | ||
168 | } else | ||
169 | if (port->type == DCB_I2C_NV4E_BIT) { | ||
170 | nv_mask(port->i2c, port->drive, 0x2f, state ? 0x21 : 0x01); | ||
171 | } else | ||
172 | if (port->type == DCB_I2C_NVIO_BIT) { | ||
173 | if (state) port->state |= 0x01; | ||
174 | else port->state &= 0xfe; | ||
175 | nv_wr32(port->i2c, port->drive, 4 | port->state); | ||
176 | } | 235 | } |
177 | } | ||
178 | |||
179 | void | ||
180 | nouveau_i2c_drive_sda(void *data, int state) | ||
181 | { | ||
182 | struct nouveau_i2c_port *port = data; | ||
183 | 236 | ||
184 | if (port->type == DCB_I2C_NV04_BIT) { | 237 | return nouveau_subdev_fini(&i2c->base, suspend); |
185 | u8 val = nv_rdvgac(port->i2c, 0, port->drive); | 238 | fail: |
186 | if (state) val |= 0x10; | 239 | list_for_each_entry_continue_reverse(port, &i2c->ports, head) { |
187 | else val &= 0xef; | 240 | nv_ofuncs(port)->init(nv_object(port)); |
188 | nv_wrvgac(port->i2c, 0, port->drive, val | 0x01); | ||
189 | } else | ||
190 | if (port->type == DCB_I2C_NV4E_BIT) { | ||
191 | nv_mask(port->i2c, port->drive, 0x1f, state ? 0x11 : 0x01); | ||
192 | } else | ||
193 | if (port->type == DCB_I2C_NVIO_BIT) { | ||
194 | if (state) port->state |= 0x02; | ||
195 | else port->state &= 0xfd; | ||
196 | nv_wr32(port->i2c, port->drive, 4 | port->state); | ||
197 | } | 241 | } |
242 | |||
243 | return ret; | ||
198 | } | 244 | } |
199 | 245 | ||
200 | int | 246 | int |
201 | nouveau_i2c_sense_scl(void *data) | 247 | _nouveau_i2c_init(struct nouveau_object *object) |
202 | { | 248 | { |
203 | struct nouveau_i2c_port *port = data; | 249 | struct nouveau_i2c *i2c = (void *)object; |
204 | struct nouveau_device *device = nv_device(port->i2c); | 250 | struct nouveau_i2c_port *port; |
205 | 251 | int ret; | |
206 | if (port->type == DCB_I2C_NV04_BIT) { | 252 | |
207 | return !!(nv_rdvgac(port->i2c, 0, port->sense) & 0x04); | 253 | ret = nouveau_subdev_init(&i2c->base); |
208 | } else | 254 | if (ret == 0) { |
209 | if (port->type == DCB_I2C_NV4E_BIT) { | 255 | list_for_each_entry(port, &i2c->ports, head) { |
210 | return !!(nv_rd32(port->i2c, port->sense) & 0x00040000); | 256 | ret = nv_ofuncs(port)->init(nv_object(port)); |
211 | } else | 257 | if (ret) |
212 | if (port->type == DCB_I2C_NVIO_BIT) { | 258 | goto fail; |
213 | if (device->card_type < NV_D0) | 259 | } |
214 | return !!(nv_rd32(port->i2c, port->sense) & 0x01); | ||
215 | else | ||
216 | return !!(nv_rd32(port->i2c, port->sense) & 0x10); | ||
217 | } | 260 | } |
218 | 261 | ||
219 | return 0; | 262 | return ret; |
263 | fail: | ||
264 | list_for_each_entry_continue_reverse(port, &i2c->ports, head) { | ||
265 | nv_ofuncs(port)->fini(nv_object(port), false); | ||
266 | } | ||
267 | |||
268 | return ret; | ||
220 | } | 269 | } |
221 | 270 | ||
222 | int | 271 | void |
223 | nouveau_i2c_sense_sda(void *data) | 272 | _nouveau_i2c_dtor(struct nouveau_object *object) |
224 | { | 273 | { |
225 | struct nouveau_i2c_port *port = data; | 274 | struct nouveau_i2c *i2c = (void *)object; |
226 | struct nouveau_device *device = nv_device(port->i2c); | 275 | struct nouveau_i2c_port *port, *temp; |
227 | 276 | ||
228 | if (port->type == DCB_I2C_NV04_BIT) { | 277 | list_for_each_entry_safe(port, temp, &i2c->ports, head) { |
229 | return !!(nv_rdvgac(port->i2c, 0, port->sense) & 0x08); | 278 | nouveau_object_ref(NULL, (struct nouveau_object **)&port); |
230 | } else | ||
231 | if (port->type == DCB_I2C_NV4E_BIT) { | ||
232 | return !!(nv_rd32(port->i2c, port->sense) & 0x00080000); | ||
233 | } else | ||
234 | if (port->type == DCB_I2C_NVIO_BIT) { | ||
235 | if (device->card_type < NV_D0) | ||
236 | return !!(nv_rd32(port->i2c, port->sense) & 0x02); | ||
237 | else | ||
238 | return !!(nv_rd32(port->i2c, port->sense) & 0x20); | ||
239 | } | 279 | } |
240 | 280 | ||
241 | return 0; | 281 | nouveau_subdev_destroy(&i2c->base); |
242 | } | 282 | } |
243 | 283 | ||
244 | static const u32 nv50_i2c_port[] = { | 284 | static struct nouveau_oclass * |
245 | 0x00e138, 0x00e150, 0x00e168, 0x00e180, | 285 | nouveau_i2c_extdev_sclass[] = { |
246 | 0x00e254, 0x00e274, 0x00e764, 0x00e780, | 286 | nouveau_anx9805_sclass, |
247 | 0x00e79c, 0x00e7b8 | ||
248 | }; | 287 | }; |
249 | 288 | ||
250 | static int | 289 | int |
251 | nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 290 | nouveau_i2c_create_(struct nouveau_object *parent, |
252 | struct nouveau_oclass *oclass, void *data, u32 size, | 291 | struct nouveau_object *engine, |
253 | struct nouveau_object **pobject) | 292 | struct nouveau_oclass *oclass, |
293 | struct nouveau_oclass *sclass, | ||
294 | int length, void **pobject) | ||
254 | { | 295 | { |
255 | struct nouveau_device *device = nv_device(parent); | ||
256 | struct nouveau_bios *bios = nouveau_bios(parent); | 296 | struct nouveau_bios *bios = nouveau_bios(parent); |
257 | struct nouveau_i2c_port *port; | ||
258 | struct nouveau_i2c *i2c; | 297 | struct nouveau_i2c *i2c; |
298 | struct nouveau_object *object; | ||
259 | struct dcb_i2c_entry info; | 299 | struct dcb_i2c_entry info; |
260 | int ret, i = -1; | 300 | int ret, i, j, index = -1; |
301 | struct dcb_output outp; | ||
302 | u8 ver, hdr; | ||
303 | u32 data; | ||
261 | 304 | ||
262 | ret = nouveau_subdev_create(parent, engine, oclass, 0, | 305 | ret = nouveau_subdev_create(parent, engine, oclass, 0, |
263 | "I2C", "i2c", &i2c); | 306 | "I2C", "i2c", &i2c); |
@@ -266,142 +309,60 @@ nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
266 | return ret; | 309 | return ret; |
267 | 310 | ||
268 | i2c->find = nouveau_i2c_find; | 311 | i2c->find = nouveau_i2c_find; |
312 | i2c->find_type = nouveau_i2c_find_type; | ||
269 | i2c->identify = nouveau_i2c_identify; | 313 | i2c->identify = nouveau_i2c_identify; |
270 | INIT_LIST_HEAD(&i2c->ports); | 314 | INIT_LIST_HEAD(&i2c->ports); |
271 | 315 | ||
272 | while (!dcb_i2c_parse(bios, ++i, &info)) { | 316 | while (!dcb_i2c_parse(bios, ++index, &info)) { |
273 | if (info.type == DCB_I2C_UNUSED) | 317 | if (info.type == DCB_I2C_UNUSED) |
274 | continue; | 318 | continue; |
275 | 319 | ||
276 | port = kzalloc(sizeof(*port), GFP_KERNEL); | 320 | oclass = sclass; |
277 | if (!port) { | 321 | do { |
278 | nv_error(i2c, "failed port memory alloc at %d\n", i); | 322 | ret = -EINVAL; |
279 | break; | 323 | if (oclass->handle == info.type) { |
280 | } | 324 | ret = nouveau_object_ctor(*pobject, *pobject, |
281 | 325 | oclass, &info, | |
282 | port->type = info.type; | 326 | index, &object); |
283 | switch (port->type) { | ||
284 | case DCB_I2C_NV04_BIT: | ||
285 | port->drive = info.drive; | ||
286 | port->sense = info.sense; | ||
287 | break; | ||
288 | case DCB_I2C_NV4E_BIT: | ||
289 | port->drive = 0x600800 + info.drive; | ||
290 | port->sense = port->drive; | ||
291 | break; | ||
292 | case DCB_I2C_NVIO_BIT: | ||
293 | port->drive = info.drive & 0x0f; | ||
294 | if (device->card_type < NV_D0) { | ||
295 | if (port->drive >= ARRAY_SIZE(nv50_i2c_port)) | ||
296 | break; | ||
297 | port->drive = nv50_i2c_port[port->drive]; | ||
298 | port->sense = port->drive; | ||
299 | } else { | ||
300 | port->drive = 0x00d014 + (port->drive * 0x20); | ||
301 | port->sense = port->drive; | ||
302 | } | 327 | } |
328 | } while (ret && (++oclass)->handle); | ||
329 | } | ||
330 | |||
331 | /* in addition to the busses specified in the i2c table, there | ||
332 | * may be ddc/aux channels hiding behind external tmds/dp/etc | ||
333 | * transmitters. | ||
334 | */ | ||
335 | index = ((index + 0x0f) / 0x10) * 0x10; | ||
336 | i = -1; | ||
337 | while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) { | ||
338 | if (!outp.location || !outp.extdev) | ||
339 | continue; | ||
340 | |||
341 | switch (outp.type) { | ||
342 | case DCB_OUTPUT_TMDS: | ||
343 | info.type = NV_I2C_TYPE_EXTDDC(outp.extdev); | ||
303 | break; | 344 | break; |
304 | case DCB_I2C_NVIO_AUX: | 345 | case DCB_OUTPUT_DP: |
305 | port->drive = info.drive & 0x0f; | 346 | info.type = NV_I2C_TYPE_EXTAUX(outp.extdev); |
306 | port->sense = port->drive; | ||
307 | port->adapter.algo = &nouveau_i2c_aux_algo; | ||
308 | break; | 347 | break; |
309 | default: | 348 | default: |
310 | break; | ||
311 | } | ||
312 | |||
313 | if (!port->adapter.algo && !port->drive) { | ||
314 | nv_error(i2c, "I2C%d: type %d index %x/%x unknown\n", | ||
315 | i, port->type, port->drive, port->sense); | ||
316 | kfree(port); | ||
317 | continue; | 349 | continue; |
318 | } | 350 | } |
319 | 351 | ||
320 | snprintf(port->adapter.name, sizeof(port->adapter.name), | 352 | ret = -ENODEV; |
321 | "nouveau-%s-%d", device->name, i); | 353 | j = -1; |
322 | port->adapter.owner = THIS_MODULE; | 354 | while (ret && ++j < ARRAY_SIZE(nouveau_i2c_extdev_sclass)) { |
323 | port->adapter.dev.parent = &device->pdev->dev; | 355 | parent = nv_object(i2c->find(i2c, outp.i2c_index)); |
324 | port->i2c = i2c; | 356 | oclass = nouveau_i2c_extdev_sclass[j]; |
325 | port->index = i; | 357 | do { |
326 | port->dcb = info.data; | 358 | if (oclass->handle != info.type) |
327 | i2c_set_adapdata(&port->adapter, i2c); | 359 | continue; |
328 | 360 | ret = nouveau_object_ctor(parent, *pobject, | |
329 | if (port->adapter.algo != &nouveau_i2c_aux_algo) { | 361 | oclass, NULL, |
330 | nouveau_i2c_drive_scl(port, 0); | 362 | index++, &object); |
331 | nouveau_i2c_drive_sda(port, 1); | 363 | } while (ret && (++oclass)->handle); |
332 | nouveau_i2c_drive_scl(port, 1); | ||
333 | |||
334 | #ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT | ||
335 | if (nouveau_boolopt(device->cfgopt, "NvI2C", true)) { | ||
336 | #else | ||
337 | if (nouveau_boolopt(device->cfgopt, "NvI2C", false)) { | ||
338 | #endif | ||
339 | port->adapter.algo = &nouveau_i2c_bit_algo; | ||
340 | ret = i2c_add_adapter(&port->adapter); | ||
341 | } else { | ||
342 | port->adapter.algo_data = &port->bit; | ||
343 | port->bit.udelay = 10; | ||
344 | port->bit.timeout = usecs_to_jiffies(2200); | ||
345 | port->bit.data = port; | ||
346 | port->bit.setsda = nouveau_i2c_drive_sda; | ||
347 | port->bit.setscl = nouveau_i2c_drive_scl; | ||
348 | port->bit.getsda = nouveau_i2c_sense_sda; | ||
349 | port->bit.getscl = nouveau_i2c_sense_scl; | ||
350 | ret = i2c_bit_add_bus(&port->adapter); | ||
351 | } | ||
352 | } else { | ||
353 | port->adapter.algo = &nouveau_i2c_aux_algo; | ||
354 | ret = i2c_add_adapter(&port->adapter); | ||
355 | } | ||
356 | |||
357 | if (ret) { | ||
358 | nv_error(i2c, "I2C%d: failed register: %d\n", i, ret); | ||
359 | kfree(port); | ||
360 | continue; | ||
361 | } | 364 | } |
362 | |||
363 | list_add_tail(&port->head, &i2c->ports); | ||
364 | } | 365 | } |
365 | 366 | ||
366 | return 0; | 367 | return 0; |
367 | } | 368 | } |
368 | |||
369 | static void | ||
370 | nouveau_i2c_dtor(struct nouveau_object *object) | ||
371 | { | ||
372 | struct nouveau_i2c *i2c = (void *)object; | ||
373 | struct nouveau_i2c_port *port, *temp; | ||
374 | |||
375 | list_for_each_entry_safe(port, temp, &i2c->ports, head) { | ||
376 | i2c_del_adapter(&port->adapter); | ||
377 | list_del(&port->head); | ||
378 | kfree(port); | ||
379 | } | ||
380 | |||
381 | nouveau_subdev_destroy(&i2c->base); | ||
382 | } | ||
383 | |||
384 | static int | ||
385 | nouveau_i2c_init(struct nouveau_object *object) | ||
386 | { | ||
387 | struct nouveau_i2c *i2c = (void *)object; | ||
388 | return nouveau_subdev_init(&i2c->base); | ||
389 | } | ||
390 | |||
391 | static int | ||
392 | nouveau_i2c_fini(struct nouveau_object *object, bool suspend) | ||
393 | { | ||
394 | struct nouveau_i2c *i2c = (void *)object; | ||
395 | return nouveau_subdev_fini(&i2c->base, suspend); | ||
396 | } | ||
397 | |||
398 | struct nouveau_oclass | ||
399 | nouveau_i2c_oclass = { | ||
400 | .handle = NV_SUBDEV(I2C, 0x00), | ||
401 | .ofuncs = &(struct nouveau_ofuncs) { | ||
402 | .ctor = nouveau_i2c_ctor, | ||
403 | .dtor = nouveau_i2c_dtor, | ||
404 | .init = nouveau_i2c_init, | ||
405 | .fini = nouveau_i2c_fini, | ||
406 | }, | ||
407 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c index 1c4c9a5c8e2e..a6e72d3b06b5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c | |||
@@ -32,25 +32,25 @@ | |||
32 | static inline void | 32 | static inline void |
33 | i2c_drive_scl(struct nouveau_i2c_port *port, int state) | 33 | i2c_drive_scl(struct nouveau_i2c_port *port, int state) |
34 | { | 34 | { |
35 | nouveau_i2c_drive_scl(port, state); | 35 | port->func->drive_scl(port, state); |
36 | } | 36 | } |
37 | 37 | ||
38 | static inline void | 38 | static inline void |
39 | i2c_drive_sda(struct nouveau_i2c_port *port, int state) | 39 | i2c_drive_sda(struct nouveau_i2c_port *port, int state) |
40 | { | 40 | { |
41 | nouveau_i2c_drive_sda(port, state); | 41 | port->func->drive_sda(port, state); |
42 | } | 42 | } |
43 | 43 | ||
44 | static inline int | 44 | static inline int |
45 | i2c_sense_scl(struct nouveau_i2c_port *port) | 45 | i2c_sense_scl(struct nouveau_i2c_port *port) |
46 | { | 46 | { |
47 | return nouveau_i2c_sense_scl(port); | 47 | return port->func->sense_scl(port); |
48 | } | 48 | } |
49 | 49 | ||
50 | static inline int | 50 | static inline int |
51 | i2c_sense_sda(struct nouveau_i2c_port *port) | 51 | i2c_sense_sda(struct nouveau_i2c_port *port) |
52 | { | 52 | { |
53 | return nouveau_i2c_sense_sda(port); | 53 | return port->func->sense_sda(port); |
54 | } | 54 | } |
55 | 55 | ||
56 | static void | 56 | static void |
@@ -77,9 +77,8 @@ i2c_start(struct nouveau_i2c_port *port) | |||
77 | { | 77 | { |
78 | int ret = 0; | 78 | int ret = 0; |
79 | 79 | ||
80 | port->state = i2c_sense_scl(port); | 80 | if (!i2c_sense_scl(port) || |
81 | port->state |= i2c_sense_sda(port) << 1; | 81 | !i2c_sense_sda(port)) { |
82 | if (port->state != 3) { | ||
83 | i2c_drive_scl(port, 0); | 82 | i2c_drive_scl(port, 0); |
84 | i2c_drive_sda(port, 1); | 83 | i2c_drive_sda(port, 1); |
85 | if (!i2c_raise_scl(port)) | 84 | if (!i2c_raise_scl(port)) |
@@ -184,10 +183,13 @@ i2c_addr(struct nouveau_i2c_port *port, struct i2c_msg *msg) | |||
184 | static int | 183 | static int |
185 | i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | 184 | i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) |
186 | { | 185 | { |
187 | struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)adap; | 186 | struct nouveau_i2c_port *port = adap->algo_data; |
188 | struct i2c_msg *msg = msgs; | 187 | struct i2c_msg *msg = msgs; |
189 | int ret = 0, mcnt = num; | 188 | int ret = 0, mcnt = num; |
190 | 189 | ||
190 | if (port->func->acquire) | ||
191 | port->func->acquire(port); | ||
192 | |||
191 | while (!ret && mcnt--) { | 193 | while (!ret && mcnt--) { |
192 | u8 remaining = msg->len; | 194 | u8 remaining = msg->len; |
193 | u8 *ptr = msg->buf; | 195 | u8 *ptr = msg->buf; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c new file mode 100644 index 000000000000..2ad18840fe63 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Ben Skeggs | ||
23 | */ | ||
24 | |||
25 | #include <subdev/i2c.h> | ||
26 | #include <subdev/vga.h> | ||
27 | |||
28 | struct nv04_i2c_priv { | ||
29 | struct nouveau_i2c base; | ||
30 | }; | ||
31 | |||
32 | struct nv04_i2c_port { | ||
33 | struct nouveau_i2c_port base; | ||
34 | u8 drive; | ||
35 | u8 sense; | ||
36 | }; | ||
37 | |||
38 | static void | ||
39 | nv04_i2c_drive_scl(struct nouveau_i2c_port *base, int state) | ||
40 | { | ||
41 | struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
42 | struct nv04_i2c_port *port = (void *)base; | ||
43 | u8 val = nv_rdvgac(priv, 0, port->drive); | ||
44 | if (state) val |= 0x20; | ||
45 | else val &= 0xdf; | ||
46 | nv_wrvgac(priv, 0, port->drive, val | 0x01); | ||
47 | } | ||
48 | |||
49 | static void | ||
50 | nv04_i2c_drive_sda(struct nouveau_i2c_port *base, int state) | ||
51 | { | ||
52 | struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
53 | struct nv04_i2c_port *port = (void *)base; | ||
54 | u8 val = nv_rdvgac(priv, 0, port->drive); | ||
55 | if (state) val |= 0x10; | ||
56 | else val &= 0xef; | ||
57 | nv_wrvgac(priv, 0, port->drive, val | 0x01); | ||
58 | } | ||
59 | |||
60 | static int | ||
61 | nv04_i2c_sense_scl(struct nouveau_i2c_port *base) | ||
62 | { | ||
63 | struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
64 | struct nv04_i2c_port *port = (void *)base; | ||
65 | return !!(nv_rdvgac(priv, 0, port->sense) & 0x04); | ||
66 | } | ||
67 | |||
68 | static int | ||
69 | nv04_i2c_sense_sda(struct nouveau_i2c_port *base) | ||
70 | { | ||
71 | struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
72 | struct nv04_i2c_port *port = (void *)base; | ||
73 | return !!(nv_rdvgac(priv, 0, port->sense) & 0x08); | ||
74 | } | ||
75 | |||
76 | static const struct nouveau_i2c_func | ||
77 | nv04_i2c_func = { | ||
78 | .drive_scl = nv04_i2c_drive_scl, | ||
79 | .drive_sda = nv04_i2c_drive_sda, | ||
80 | .sense_scl = nv04_i2c_sense_scl, | ||
81 | .sense_sda = nv04_i2c_sense_sda, | ||
82 | }; | ||
83 | |||
84 | static int | ||
85 | nv04_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
86 | struct nouveau_oclass *oclass, void *data, u32 index, | ||
87 | struct nouveau_object **pobject) | ||
88 | { | ||
89 | struct dcb_i2c_entry *info = data; | ||
90 | struct nv04_i2c_port *port; | ||
91 | int ret; | ||
92 | |||
93 | ret = nouveau_i2c_port_create(parent, engine, oclass, index, | ||
94 | &nouveau_i2c_bit_algo, &port); | ||
95 | *pobject = nv_object(port); | ||
96 | if (ret) | ||
97 | return ret; | ||
98 | |||
99 | port->base.func = &nv04_i2c_func; | ||
100 | port->drive = info->drive; | ||
101 | port->sense = info->sense; | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static struct nouveau_oclass | ||
106 | nv04_i2c_sclass[] = { | ||
107 | { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV04_BIT), | ||
108 | .ofuncs = &(struct nouveau_ofuncs) { | ||
109 | .ctor = nv04_i2c_port_ctor, | ||
110 | .dtor = _nouveau_i2c_port_dtor, | ||
111 | .init = _nouveau_i2c_port_init, | ||
112 | .fini = _nouveau_i2c_port_fini, | ||
113 | }, | ||
114 | }, | ||
115 | {} | ||
116 | }; | ||
117 | |||
118 | static int | ||
119 | nv04_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
120 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
121 | struct nouveau_object **pobject) | ||
122 | { | ||
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, | ||
140 | .init = _nouveau_i2c_init, | ||
141 | .fini = _nouveau_i2c_fini, | ||
142 | }, | ||
143 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c new file mode 100644 index 000000000000..f501ae25dbb3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Ben Skeggs | ||
23 | */ | ||
24 | |||
25 | #include <subdev/i2c.h> | ||
26 | #include <subdev/vga.h> | ||
27 | |||
28 | struct nv4e_i2c_priv { | ||
29 | struct nouveau_i2c base; | ||
30 | }; | ||
31 | |||
32 | struct nv4e_i2c_port { | ||
33 | struct nouveau_i2c_port base; | ||
34 | u32 addr; | ||
35 | }; | ||
36 | |||
37 | static void | ||
38 | nv4e_i2c_drive_scl(struct nouveau_i2c_port *base, int state) | ||
39 | { | ||
40 | struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
41 | struct nv4e_i2c_port *port = (void *)base; | ||
42 | nv_mask(priv, port->addr, 0x2f, state ? 0x21 : 0x01); | ||
43 | } | ||
44 | |||
45 | static void | ||
46 | nv4e_i2c_drive_sda(struct nouveau_i2c_port *base, int state) | ||
47 | { | ||
48 | struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
49 | struct nv4e_i2c_port *port = (void *)base; | ||
50 | nv_mask(priv, port->addr, 0x1f, state ? 0x11 : 0x01); | ||
51 | } | ||
52 | |||
53 | static int | ||
54 | nv4e_i2c_sense_scl(struct nouveau_i2c_port *base) | ||
55 | { | ||
56 | struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
57 | struct nv4e_i2c_port *port = (void *)base; | ||
58 | return !!(nv_rd32(priv, port->addr) & 0x00040000); | ||
59 | } | ||
60 | |||
61 | static int | ||
62 | nv4e_i2c_sense_sda(struct nouveau_i2c_port *base) | ||
63 | { | ||
64 | struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
65 | struct nv4e_i2c_port *port = (void *)base; | ||
66 | return !!(nv_rd32(priv, port->addr) & 0x00080000); | ||
67 | } | ||
68 | |||
69 | static const struct nouveau_i2c_func | ||
70 | nv4e_i2c_func = { | ||
71 | .drive_scl = nv4e_i2c_drive_scl, | ||
72 | .drive_sda = nv4e_i2c_drive_sda, | ||
73 | .sense_scl = nv4e_i2c_sense_scl, | ||
74 | .sense_sda = nv4e_i2c_sense_sda, | ||
75 | }; | ||
76 | |||
77 | static int | ||
78 | nv4e_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
79 | struct nouveau_oclass *oclass, void *data, u32 index, | ||
80 | struct nouveau_object **pobject) | ||
81 | { | ||
82 | struct dcb_i2c_entry *info = data; | ||
83 | struct nv4e_i2c_port *port; | ||
84 | int ret; | ||
85 | |||
86 | ret = nouveau_i2c_port_create(parent, engine, oclass, index, | ||
87 | &nouveau_i2c_bit_algo, &port); | ||
88 | *pobject = nv_object(port); | ||
89 | if (ret) | ||
90 | return ret; | ||
91 | |||
92 | port->base.func = &nv4e_i2c_func; | ||
93 | port->addr = 0x600800 + info->drive; | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static struct nouveau_oclass | ||
98 | nv4e_i2c_sclass[] = { | ||
99 | { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV4E_BIT), | ||
100 | .ofuncs = &(struct nouveau_ofuncs) { | ||
101 | .ctor = nv4e_i2c_port_ctor, | ||
102 | .dtor = _nouveau_i2c_port_dtor, | ||
103 | .init = _nouveau_i2c_port_init, | ||
104 | .fini = _nouveau_i2c_port_fini, | ||
105 | }, | ||
106 | }, | ||
107 | {} | ||
108 | }; | ||
109 | |||
110 | static int | ||
111 | nv4e_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
112 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
113 | struct nouveau_object **pobject) | ||
114 | { | ||
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, | ||
132 | .init = _nouveau_i2c_init, | ||
133 | .fini = _nouveau_i2c_fini, | ||
134 | }, | ||
135 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c new file mode 100644 index 000000000000..378dfa324e5f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c | |||
@@ -0,0 +1,149 @@ | |||
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 | void | ||
28 | nv50_i2c_drive_scl(struct nouveau_i2c_port *base, int state) | ||
29 | { | ||
30 | struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
31 | struct nv50_i2c_port *port = (void *)base; | ||
32 | if (state) port->state |= 0x01; | ||
33 | else port->state &= 0xfe; | ||
34 | nv_wr32(priv, port->addr, port->state); | ||
35 | } | ||
36 | |||
37 | void | ||
38 | nv50_i2c_drive_sda(struct nouveau_i2c_port *base, int state) | ||
39 | { | ||
40 | struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
41 | struct nv50_i2c_port *port = (void *)base; | ||
42 | if (state) port->state |= 0x02; | ||
43 | else port->state &= 0xfd; | ||
44 | nv_wr32(priv, port->addr, port->state); | ||
45 | } | ||
46 | |||
47 | int | ||
48 | nv50_i2c_sense_scl(struct nouveau_i2c_port *base) | ||
49 | { | ||
50 | struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
51 | struct nv50_i2c_port *port = (void *)base; | ||
52 | return !!(nv_rd32(priv, port->addr) & 0x00000001); | ||
53 | } | ||
54 | |||
55 | int | ||
56 | nv50_i2c_sense_sda(struct nouveau_i2c_port *base) | ||
57 | { | ||
58 | struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
59 | struct nv50_i2c_port *port = (void *)base; | ||
60 | return !!(nv_rd32(priv, port->addr) & 0x00000002); | ||
61 | } | ||
62 | |||
63 | static const struct nouveau_i2c_func | ||
64 | nv50_i2c_func = { | ||
65 | .drive_scl = nv50_i2c_drive_scl, | ||
66 | .drive_sda = nv50_i2c_drive_sda, | ||
67 | .sense_scl = nv50_i2c_sense_scl, | ||
68 | .sense_sda = nv50_i2c_sense_sda, | ||
69 | }; | ||
70 | |||
71 | const u32 nv50_i2c_addr[] = { | ||
72 | 0x00e138, 0x00e150, 0x00e168, 0x00e180, | ||
73 | 0x00e254, 0x00e274, 0x00e764, 0x00e780, | ||
74 | 0x00e79c, 0x00e7b8 | ||
75 | }; | ||
76 | const int nv50_i2c_addr_nr = ARRAY_SIZE(nv50_i2c_addr); | ||
77 | |||
78 | static int | ||
79 | nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
80 | struct nouveau_oclass *oclass, void *data, u32 index, | ||
81 | struct nouveau_object **pobject) | ||
82 | { | ||
83 | struct dcb_i2c_entry *info = data; | ||
84 | struct nv50_i2c_port *port; | ||
85 | int ret; | ||
86 | |||
87 | ret = nouveau_i2c_port_create(parent, engine, oclass, index, | ||
88 | &nouveau_i2c_bit_algo, &port); | ||
89 | *pobject = nv_object(port); | ||
90 | if (ret) | ||
91 | return ret; | ||
92 | |||
93 | if (info->drive >= nv50_i2c_addr_nr) | ||
94 | return -EINVAL; | ||
95 | |||
96 | port->base.func = &nv50_i2c_func; | ||
97 | port->state = 0x00000007; | ||
98 | port->addr = nv50_i2c_addr[info->drive]; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | int | ||
103 | nv50_i2c_port_init(struct nouveau_object *object) | ||
104 | { | ||
105 | struct nv50_i2c_priv *priv = (void *)object->engine; | ||
106 | struct nv50_i2c_port *port = (void *)object; | ||
107 | nv_wr32(priv, port->addr, port->state); | ||
108 | return nouveau_i2c_port_init(&port->base); | ||
109 | } | ||
110 | |||
111 | static struct nouveau_oclass | ||
112 | nv50_i2c_sclass[] = { | ||
113 | { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), | ||
114 | .ofuncs = &(struct nouveau_ofuncs) { | ||
115 | .ctor = nv50_i2c_port_ctor, | ||
116 | .dtor = _nouveau_i2c_port_dtor, | ||
117 | .init = nv50_i2c_port_init, | ||
118 | .fini = _nouveau_i2c_port_fini, | ||
119 | }, | ||
120 | }, | ||
121 | {} | ||
122 | }; | ||
123 | |||
124 | static int | ||
125 | nv50_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
126 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
127 | struct nouveau_object **pobject) | ||
128 | { | ||
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, | ||
146 | .init = _nouveau_i2c_init, | ||
147 | .fini = _nouveau_i2c_fini, | ||
148 | }, | ||
149 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h new file mode 100644 index 000000000000..4e5ba48ebf5a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h | |||
@@ -0,0 +1,32 @@ | |||
1 | #ifndef __NV50_I2C_H__ | ||
2 | #define __NV50_I2C_H__ | ||
3 | |||
4 | #include <subdev/i2c.h> | ||
5 | |||
6 | struct nv50_i2c_priv { | ||
7 | struct nouveau_i2c base; | ||
8 | }; | ||
9 | |||
10 | struct nv50_i2c_port { | ||
11 | struct nouveau_i2c_port base; | ||
12 | u32 addr; | ||
13 | u32 ctrl; | ||
14 | u32 data; | ||
15 | u32 state; | ||
16 | }; | ||
17 | |||
18 | extern const u32 nv50_i2c_addr[]; | ||
19 | extern const int nv50_i2c_addr_nr; | ||
20 | int nv50_i2c_port_init(struct nouveau_object *); | ||
21 | int nv50_i2c_sense_scl(struct nouveau_i2c_port *); | ||
22 | int nv50_i2c_sense_sda(struct nouveau_i2c_port *); | ||
23 | void nv50_i2c_drive_scl(struct nouveau_i2c_port *, int state); | ||
24 | void nv50_i2c_drive_sda(struct nouveau_i2c_port *, int state); | ||
25 | |||
26 | int nv94_aux_port_ctor(struct nouveau_object *, struct nouveau_object *, | ||
27 | struct nouveau_oclass *, void *, u32, | ||
28 | struct nouveau_object **); | ||
29 | void nv94_i2c_acquire(struct nouveau_i2c_port *); | ||
30 | void nv94_i2c_release(struct nouveau_i2c_port *); | ||
31 | |||
32 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c new file mode 100644 index 000000000000..61b771670bfe --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c | |||
@@ -0,0 +1,285 @@ | |||
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 | #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) | ||
29 | |||
30 | static void | ||
31 | auxch_fini(struct nouveau_i2c *aux, int ch) | ||
32 | { | ||
33 | nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); | ||
34 | } | ||
35 | |||
36 | static int | ||
37 | auxch_init(struct nouveau_i2c *aux, int ch) | ||
38 | { | ||
39 | const u32 unksel = 1; /* nfi which to use, or if it matters.. */ | ||
40 | const u32 ureq = unksel ? 0x00100000 : 0x00200000; | ||
41 | const u32 urep = unksel ? 0x01000000 : 0x02000000; | ||
42 | u32 ctrl, timeout; | ||
43 | |||
44 | /* wait up to 1ms for any previous transaction to be done... */ | ||
45 | timeout = 1000; | ||
46 | do { | ||
47 | ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); | ||
48 | udelay(1); | ||
49 | if (!timeout--) { | ||
50 | AUX_ERR("begin idle timeout 0x%08x\n", ctrl); | ||
51 | return -EBUSY; | ||
52 | } | ||
53 | } while (ctrl & 0x03010000); | ||
54 | |||
55 | /* set some magic, and wait up to 1ms for it to appear */ | ||
56 | nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); | ||
57 | timeout = 1000; | ||
58 | do { | ||
59 | ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); | ||
60 | udelay(1); | ||
61 | if (!timeout--) { | ||
62 | AUX_ERR("magic wait 0x%08x\n", ctrl); | ||
63 | auxch_fini(aux, ch); | ||
64 | return -EBUSY; | ||
65 | } | ||
66 | } while ((ctrl & 0x03000000) != urep); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | int | ||
72 | nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) | ||
73 | { | ||
74 | struct nouveau_i2c *aux = nouveau_i2c(base); | ||
75 | struct nv50_i2c_port *port = (void *)base; | ||
76 | u32 ctrl, stat, timeout, retries; | ||
77 | u32 xbuf[4] = {}; | ||
78 | int ch = port->addr; | ||
79 | int ret, i; | ||
80 | |||
81 | AUX_DBG("%d: 0x%08x %d\n", type, addr, size); | ||
82 | |||
83 | ret = auxch_init(aux, ch); | ||
84 | if (ret) | ||
85 | goto out; | ||
86 | |||
87 | stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50)); | ||
88 | if (!(stat & 0x10000000)) { | ||
89 | AUX_DBG("sink not detected\n"); | ||
90 | ret = -ENXIO; | ||
91 | goto out; | ||
92 | } | ||
93 | |||
94 | if (!(type & 1)) { | ||
95 | memcpy(xbuf, data, size); | ||
96 | for (i = 0; i < 16; i += 4) { | ||
97 | AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); | ||
98 | nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); | ||
103 | ctrl &= ~0x0001f0ff; | ||
104 | ctrl |= type << 12; | ||
105 | ctrl |= size - 1; | ||
106 | nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr); | ||
107 | |||
108 | /* retry transaction a number of times on failure... */ | ||
109 | ret = -EREMOTEIO; | ||
110 | for (retries = 0; retries < 32; retries++) { | ||
111 | /* reset, and delay a while if this is a retry */ | ||
112 | nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); | ||
113 | nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); | ||
114 | if (retries) | ||
115 | udelay(400); | ||
116 | |||
117 | /* transaction request, wait up to 1ms for it to complete */ | ||
118 | nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); | ||
119 | |||
120 | timeout = 1000; | ||
121 | do { | ||
122 | ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); | ||
123 | udelay(1); | ||
124 | if (!timeout--) { | ||
125 | AUX_ERR("tx req timeout 0x%08x\n", ctrl); | ||
126 | goto out; | ||
127 | } | ||
128 | } while (ctrl & 0x00010000); | ||
129 | |||
130 | /* read status, and check if transaction completed ok */ | ||
131 | stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0); | ||
132 | if (!(stat & 0x000f0f00)) { | ||
133 | ret = 0; | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); | ||
138 | } | ||
139 | |||
140 | if (type & 1) { | ||
141 | for (i = 0; i < 16; i += 4) { | ||
142 | xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i); | ||
143 | AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); | ||
144 | } | ||
145 | memcpy(data, xbuf, size); | ||
146 | } | ||
147 | |||
148 | out: | ||
149 | auxch_fini(aux, ch); | ||
150 | return ret; | ||
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 | } | ||
168 | |||
169 | static const struct nouveau_i2c_func | ||
170 | nv94_i2c_func = { | ||
171 | .acquire = nv94_i2c_acquire, | ||
172 | .release = nv94_i2c_release, | ||
173 | .drive_scl = nv50_i2c_drive_scl, | ||
174 | .drive_sda = nv50_i2c_drive_sda, | ||
175 | .sense_scl = nv50_i2c_sense_scl, | ||
176 | .sense_sda = nv50_i2c_sense_sda, | ||
177 | }; | ||
178 | |||
179 | static int | ||
180 | nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
181 | struct nouveau_oclass *oclass, void *data, u32 index, | ||
182 | struct nouveau_object **pobject) | ||
183 | { | ||
184 | struct dcb_i2c_entry *info = data; | ||
185 | struct nv50_i2c_port *port; | ||
186 | int ret; | ||
187 | |||
188 | ret = nouveau_i2c_port_create(parent, engine, oclass, index, | ||
189 | &nouveau_i2c_bit_algo, &port); | ||
190 | *pobject = nv_object(port); | ||
191 | if (ret) | ||
192 | return ret; | ||
193 | |||
194 | if (info->drive >= nv50_i2c_addr_nr) | ||
195 | return -EINVAL; | ||
196 | |||
197 | port->base.func = &nv94_i2c_func; | ||
198 | port->state = 7; | ||
199 | port->addr = nv50_i2c_addr[info->drive]; | ||
200 | if (info->share != DCB_I2C_UNUSED) { | ||
201 | port->ctrl = 0x00e500 + (info->share * 0x50); | ||
202 | port->data = 0x0000e001; | ||
203 | } | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static const struct nouveau_i2c_func | ||
208 | nv94_aux_func = { | ||
209 | .acquire = nv94_i2c_acquire, | ||
210 | .release = nv94_i2c_release, | ||
211 | .aux = nv94_aux, | ||
212 | }; | ||
213 | |||
214 | int | ||
215 | nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
216 | struct nouveau_oclass *oclass, void *data, u32 index, | ||
217 | struct nouveau_object **pobject) | ||
218 | { | ||
219 | struct dcb_i2c_entry *info = data; | ||
220 | struct nv50_i2c_port *port; | ||
221 | int ret; | ||
222 | |||
223 | ret = nouveau_i2c_port_create(parent, engine, oclass, index, | ||
224 | &nouveau_i2c_aux_algo, &port); | ||
225 | *pobject = nv_object(port); | ||
226 | if (ret) | ||
227 | return ret; | ||
228 | |||
229 | port->base.func = &nv94_aux_func; | ||
230 | port->addr = info->drive; | ||
231 | if (info->share != DCB_I2C_UNUSED) { | ||
232 | port->ctrl = 0x00e500 + (info->drive * 0x50); | ||
233 | port->data = 0x00002002; | ||
234 | } | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static struct nouveau_oclass | ||
240 | nv94_i2c_sclass[] = { | ||
241 | { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), | ||
242 | .ofuncs = &(struct nouveau_ofuncs) { | ||
243 | .ctor = nv94_i2c_port_ctor, | ||
244 | .dtor = _nouveau_i2c_port_dtor, | ||
245 | .init = nv50_i2c_port_init, | ||
246 | .fini = _nouveau_i2c_port_fini, | ||
247 | }, | ||
248 | }, | ||
249 | { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX), | ||
250 | .ofuncs = &(struct nouveau_ofuncs) { | ||
251 | .ctor = nv94_aux_port_ctor, | ||
252 | .dtor = _nouveau_i2c_port_dtor, | ||
253 | .init = _nouveau_i2c_port_init, | ||
254 | .fini = _nouveau_i2c_port_fini, | ||
255 | }, | ||
256 | }, | ||
257 | {} | ||
258 | }; | ||
259 | |||
260 | static int | ||
261 | nv94_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
262 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
263 | struct nouveau_object **pobject) | ||
264 | { | ||
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, | ||
282 | .init = _nouveau_i2c_init, | ||
283 | .fini = _nouveau_i2c_fini, | ||
284 | }, | ||
285 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c new file mode 100644 index 000000000000..f761b8a610f1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c | |||
@@ -0,0 +1,124 @@ | |||
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 int | ||
28 | nvd0_i2c_sense_scl(struct nouveau_i2c_port *base) | ||
29 | { | ||
30 | struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
31 | struct nv50_i2c_port *port = (void *)base; | ||
32 | return !!(nv_rd32(priv, port->addr) & 0x00000010); | ||
33 | } | ||
34 | |||
35 | static int | ||
36 | nvd0_i2c_sense_sda(struct nouveau_i2c_port *base) | ||
37 | { | ||
38 | struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine; | ||
39 | struct nv50_i2c_port *port = (void *)base; | ||
40 | return !!(nv_rd32(priv, port->addr) & 0x00000020); | ||
41 | } | ||
42 | |||
43 | static const struct nouveau_i2c_func | ||
44 | nvd0_i2c_func = { | ||
45 | .acquire = nv94_i2c_acquire, | ||
46 | .release = nv94_i2c_release, | ||
47 | .drive_scl = nv50_i2c_drive_scl, | ||
48 | .drive_sda = nv50_i2c_drive_sda, | ||
49 | .sense_scl = nvd0_i2c_sense_scl, | ||
50 | .sense_sda = nvd0_i2c_sense_sda, | ||
51 | }; | ||
52 | |||
53 | static int | ||
54 | nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
55 | struct nouveau_oclass *oclass, void *data, u32 index, | ||
56 | struct nouveau_object **pobject) | ||
57 | { | ||
58 | struct dcb_i2c_entry *info = data; | ||
59 | struct nv50_i2c_port *port; | ||
60 | int ret; | ||
61 | |||
62 | ret = nouveau_i2c_port_create(parent, engine, oclass, index, | ||
63 | &nouveau_i2c_bit_algo, &port); | ||
64 | *pobject = nv_object(port); | ||
65 | if (ret) | ||
66 | return ret; | ||
67 | |||
68 | port->base.func = &nvd0_i2c_func; | ||
69 | port->state = 0x00000007; | ||
70 | port->addr = 0x00d014 + (info->drive * 0x20); | ||
71 | if (info->share != DCB_I2C_UNUSED) { | ||
72 | port->ctrl = 0x00e500 + (info->share * 0x50); | ||
73 | port->data = 0x0000e001; | ||
74 | } | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static struct nouveau_oclass | ||
79 | nvd0_i2c_sclass[] = { | ||
80 | { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), | ||
81 | .ofuncs = &(struct nouveau_ofuncs) { | ||
82 | .ctor = nvd0_i2c_port_ctor, | ||
83 | .dtor = _nouveau_i2c_port_dtor, | ||
84 | .init = nv50_i2c_port_init, | ||
85 | .fini = _nouveau_i2c_port_fini, | ||
86 | }, | ||
87 | }, | ||
88 | { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX), | ||
89 | .ofuncs = &(struct nouveau_ofuncs) { | ||
90 | .ctor = nv94_aux_port_ctor, | ||
91 | .dtor = _nouveau_i2c_port_dtor, | ||
92 | .init = _nouveau_i2c_port_init, | ||
93 | .fini = _nouveau_i2c_port_fini, | ||
94 | }, | ||
95 | }, | ||
96 | {} | ||
97 | }; | ||
98 | |||
99 | static int | ||
100 | nvd0_i2c_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 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, | ||
121 | .init = _nouveau_i2c_init, | ||
122 | .fini = _nouveau_i2c_fini, | ||
123 | }, | ||
124 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c index 23ebe477a6f0..89da8fa7ea0f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c | |||
@@ -37,7 +37,7 @@ nv04_mc_intr[] = { | |||
37 | { 0x00100000, NVDEV_SUBDEV_TIMER }, | 37 | { 0x00100000, NVDEV_SUBDEV_TIMER }, |
38 | { 0x01000000, NVDEV_ENGINE_DISP }, /* NV04- PCRTC0 */ | 38 | { 0x01000000, NVDEV_ENGINE_DISP }, /* NV04- PCRTC0 */ |
39 | { 0x02000000, NVDEV_ENGINE_DISP }, /* NV11- PCRTC1 */ | 39 | { 0x02000000, NVDEV_ENGINE_DISP }, /* NV11- PCRTC1 */ |
40 | { 0x10000000, NVDEV_SUBDEV_GPIO }, /* PBUS */ | 40 | { 0x10000000, NVDEV_SUBDEV_BUS }, |
41 | { 0x80000000, NVDEV_ENGINE_SW }, | 41 | { 0x80000000, NVDEV_ENGINE_SW }, |
42 | {} | 42 | {} |
43 | }; | 43 | }; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c index 8d759f830323..5965add6daee 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c | |||
@@ -38,6 +38,7 @@ nv50_mc_intr[] = { | |||
38 | { 0x00100000, NVDEV_SUBDEV_TIMER }, | 38 | { 0x00100000, NVDEV_SUBDEV_TIMER }, |
39 | { 0x00200000, NVDEV_SUBDEV_GPIO }, | 39 | { 0x00200000, NVDEV_SUBDEV_GPIO }, |
40 | { 0x04000000, NVDEV_ENGINE_DISP }, | 40 | { 0x04000000, NVDEV_ENGINE_DISP }, |
41 | { 0x10000000, NVDEV_SUBDEV_BUS }, | ||
41 | { 0x80000000, NVDEV_ENGINE_SW }, | 42 | { 0x80000000, NVDEV_ENGINE_SW }, |
42 | { 0x0000d101, NVDEV_SUBDEV_FB }, | 43 | { 0x0000d101, NVDEV_SUBDEV_FB }, |
43 | {}, | 44 | {}, |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c index ceb5c83f9459..3a80b29dce0f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c | |||
@@ -35,10 +35,12 @@ nv98_mc_intr[] = { | |||
35 | { 0x00001000, NVDEV_ENGINE_GR }, | 35 | { 0x00001000, NVDEV_ENGINE_GR }, |
36 | { 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84:NVA3 */ | 36 | { 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84:NVA3 */ |
37 | { 0x00008000, NVDEV_ENGINE_BSP }, | 37 | { 0x00008000, NVDEV_ENGINE_BSP }, |
38 | { 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */ | ||
38 | { 0x00100000, NVDEV_SUBDEV_TIMER }, | 39 | { 0x00100000, NVDEV_SUBDEV_TIMER }, |
39 | { 0x00200000, NVDEV_SUBDEV_GPIO }, | 40 | { 0x00200000, NVDEV_SUBDEV_GPIO }, |
40 | { 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */ | 41 | { 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */ |
41 | { 0x04000000, NVDEV_ENGINE_DISP }, | 42 | { 0x04000000, NVDEV_ENGINE_DISP }, |
43 | { 0x10000000, NVDEV_SUBDEV_BUS }, | ||
42 | { 0x80000000, NVDEV_ENGINE_SW }, | 44 | { 0x80000000, NVDEV_ENGINE_SW }, |
43 | { 0x0040d101, NVDEV_SUBDEV_FB }, | 45 | { 0x0040d101, NVDEV_SUBDEV_FB }, |
44 | {}, | 46 | {}, |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c index 92796682722d..42bbf72023a8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c | |||
@@ -36,11 +36,13 @@ nvc0_mc_intr[] = { | |||
36 | { 0x00000100, NVDEV_ENGINE_FIFO }, | 36 | { 0x00000100, NVDEV_ENGINE_FIFO }, |
37 | { 0x00001000, NVDEV_ENGINE_GR }, | 37 | { 0x00001000, NVDEV_ENGINE_GR }, |
38 | { 0x00008000, NVDEV_ENGINE_BSP }, | 38 | { 0x00008000, NVDEV_ENGINE_BSP }, |
39 | { 0x00040000, NVDEV_SUBDEV_THERM }, | ||
39 | { 0x00020000, NVDEV_ENGINE_VP }, | 40 | { 0x00020000, NVDEV_ENGINE_VP }, |
40 | { 0x00100000, NVDEV_SUBDEV_TIMER }, | 41 | { 0x00100000, NVDEV_SUBDEV_TIMER }, |
41 | { 0x00200000, NVDEV_SUBDEV_GPIO }, | 42 | { 0x00200000, NVDEV_SUBDEV_GPIO }, |
42 | { 0x02000000, NVDEV_SUBDEV_LTCG }, | 43 | { 0x02000000, NVDEV_SUBDEV_LTCG }, |
43 | { 0x04000000, NVDEV_ENGINE_DISP }, | 44 | { 0x04000000, NVDEV_ENGINE_DISP }, |
45 | { 0x10000000, NVDEV_SUBDEV_BUS }, | ||
44 | { 0x40000000, NVDEV_SUBDEV_IBUS }, | 46 | { 0x40000000, NVDEV_SUBDEV_IBUS }, |
45 | { 0x80000000, NVDEV_ENGINE_SW }, | 47 | { 0x80000000, NVDEV_ENGINE_SW }, |
46 | {}, | 48 | {}, |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c index 839ca1edc132..4bde7f7f7b81 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c | |||
@@ -156,15 +156,15 @@ mxms_foreach(struct nouveau_mxm *mxm, u8 types, | |||
156 | 156 | ||
157 | nv_debug(mxm, "%4s: ", mxms_desc_name[type]); | 157 | nv_debug(mxm, "%4s: ", mxms_desc_name[type]); |
158 | for (j = headerlen - 1; j >= 0; j--) | 158 | for (j = headerlen - 1; j >= 0; j--) |
159 | printk("%02x", dump[j]); | 159 | pr_cont("%02x", dump[j]); |
160 | printk("\n"); | 160 | pr_cont("\n"); |
161 | dump += headerlen; | 161 | dump += headerlen; |
162 | 162 | ||
163 | for (i = 0; i < entries; i++, dump += recordlen) { | 163 | for (i = 0; i < entries; i++, dump += recordlen) { |
164 | nv_debug(mxm, " "); | 164 | nv_debug(mxm, " "); |
165 | for (j = recordlen - 1; j >= 0; j--) | 165 | for (j = recordlen - 1; j >= 0; j--) |
166 | printk("%02x", dump[j]); | 166 | pr_cont("%02x", dump[j]); |
167 | printk("\n"); | 167 | pr_cont("\n"); |
168 | } | 168 | } |
169 | } | 169 | } |
170 | 170 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c index 1674c74a76c8..f794dc89a3b2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c | |||
@@ -29,6 +29,134 @@ | |||
29 | 29 | ||
30 | #include "priv.h" | 30 | #include "priv.h" |
31 | 31 | ||
32 | static int | ||
33 | nouveau_therm_update_trip(struct nouveau_therm *therm) | ||
34 | { | ||
35 | struct nouveau_therm_priv *priv = (void *)therm; | ||
36 | struct nouveau_therm_trip_point *trip = priv->fan->bios.trip, | ||
37 | *cur_trip = NULL, | ||
38 | *last_trip = priv->last_trip; | ||
39 | u8 temp = therm->temp_get(therm); | ||
40 | u16 duty, i; | ||
41 | |||
42 | /* look for the trip point corresponding to the current temperature */ | ||
43 | cur_trip = NULL; | ||
44 | for (i = 0; i < priv->fan->bios.nr_fan_trip; i++) { | ||
45 | if (temp >= trip[i].temp) | ||
46 | cur_trip = &trip[i]; | ||
47 | } | ||
48 | |||
49 | /* account for the hysteresis cycle */ | ||
50 | if (last_trip && temp <= (last_trip->temp) && | ||
51 | temp > (last_trip->temp - last_trip->hysteresis)) | ||
52 | cur_trip = last_trip; | ||
53 | |||
54 | if (cur_trip) { | ||
55 | duty = cur_trip->fan_duty; | ||
56 | priv->last_trip = cur_trip; | ||
57 | } else { | ||
58 | duty = 0; | ||
59 | priv->last_trip = NULL; | ||
60 | } | ||
61 | |||
62 | return duty; | ||
63 | } | ||
64 | |||
65 | static int | ||
66 | nouveau_therm_update_linear(struct nouveau_therm *therm) | ||
67 | { | ||
68 | struct nouveau_therm_priv *priv = (void *)therm; | ||
69 | u8 linear_min_temp = priv->fan->bios.linear_min_temp; | ||
70 | u8 linear_max_temp = priv->fan->bios.linear_max_temp; | ||
71 | u8 temp = therm->temp_get(therm); | ||
72 | u16 duty; | ||
73 | |||
74 | /* handle the non-linear part first */ | ||
75 | if (temp < linear_min_temp) | ||
76 | return priv->fan->bios.min_duty; | ||
77 | else if (temp > linear_max_temp) | ||
78 | return priv->fan->bios.max_duty; | ||
79 | |||
80 | /* we are in the linear zone */ | ||
81 | duty = (temp - linear_min_temp); | ||
82 | duty *= (priv->fan->bios.max_duty - priv->fan->bios.min_duty); | ||
83 | duty /= (linear_max_temp - linear_min_temp); | ||
84 | duty += priv->fan->bios.min_duty; | ||
85 | |||
86 | return duty; | ||
87 | } | ||
88 | |||
89 | static void | ||
90 | nouveau_therm_update(struct nouveau_therm *therm, int mode) | ||
91 | { | ||
92 | struct nouveau_timer *ptimer = nouveau_timer(therm); | ||
93 | struct nouveau_therm_priv *priv = (void *)therm; | ||
94 | unsigned long flags; | ||
95 | int duty; | ||
96 | |||
97 | spin_lock_irqsave(&priv->lock, flags); | ||
98 | if (mode < 0) | ||
99 | mode = priv->mode; | ||
100 | priv->mode = mode; | ||
101 | |||
102 | switch (mode) { | ||
103 | case NOUVEAU_THERM_CTRL_MANUAL: | ||
104 | duty = nouveau_therm_fan_get(therm); | ||
105 | if (duty < 0) | ||
106 | duty = 100; | ||
107 | break; | ||
108 | case NOUVEAU_THERM_CTRL_AUTO: | ||
109 | if (priv->fan->bios.nr_fan_trip) | ||
110 | duty = nouveau_therm_update_trip(therm); | ||
111 | else | ||
112 | duty = nouveau_therm_update_linear(therm); | ||
113 | break; | ||
114 | case NOUVEAU_THERM_CTRL_NONE: | ||
115 | default: | ||
116 | goto done; | ||
117 | } | ||
118 | |||
119 | nv_debug(therm, "FAN target request: %d%%\n", duty); | ||
120 | nouveau_therm_fan_set(therm, (mode != NOUVEAU_THERM_CTRL_AUTO), duty); | ||
121 | |||
122 | done: | ||
123 | if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO)) | ||
124 | ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm); | ||
125 | spin_unlock_irqrestore(&priv->lock, flags); | ||
126 | } | ||
127 | |||
128 | static void | ||
129 | nouveau_therm_alarm(struct nouveau_alarm *alarm) | ||
130 | { | ||
131 | struct nouveau_therm_priv *priv = | ||
132 | container_of(alarm, struct nouveau_therm_priv, alarm); | ||
133 | nouveau_therm_update(&priv->base, -1); | ||
134 | } | ||
135 | |||
136 | int | ||
137 | nouveau_therm_mode(struct nouveau_therm *therm, int mode) | ||
138 | { | ||
139 | struct nouveau_therm_priv *priv = (void *)therm; | ||
140 | struct nouveau_device *device = nv_device(therm); | ||
141 | static const char *name[] = { | ||
142 | "disabled", | ||
143 | "manual", | ||
144 | "automatic" | ||
145 | }; | ||
146 | |||
147 | /* The default PDAEMON ucode interferes with fan management */ | ||
148 | if ((mode >= ARRAY_SIZE(name)) || | ||
149 | (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0)) | ||
150 | return -EINVAL; | ||
151 | |||
152 | if (priv->mode == mode) | ||
153 | return 0; | ||
154 | |||
155 | nv_info(therm, "Thermal management: %s\n", name[mode]); | ||
156 | nouveau_therm_update(therm, mode); | ||
157 | return 0; | ||
158 | } | ||
159 | |||
32 | int | 160 | int |
33 | nouveau_therm_attr_get(struct nouveau_therm *therm, | 161 | nouveau_therm_attr_get(struct nouveau_therm *therm, |
34 | enum nouveau_therm_attr_type type) | 162 | enum nouveau_therm_attr_type type) |
@@ -37,11 +165,11 @@ nouveau_therm_attr_get(struct nouveau_therm *therm, | |||
37 | 165 | ||
38 | switch (type) { | 166 | switch (type) { |
39 | case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY: | 167 | case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY: |
40 | return priv->bios_fan.min_duty; | 168 | return priv->fan->bios.min_duty; |
41 | case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY: | 169 | case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY: |
42 | return priv->bios_fan.max_duty; | 170 | return priv->fan->bios.max_duty; |
43 | case NOUVEAU_THERM_ATTR_FAN_MODE: | 171 | case NOUVEAU_THERM_ATTR_FAN_MODE: |
44 | return priv->fan.mode; | 172 | return priv->mode; |
45 | case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: | 173 | case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: |
46 | return priv->bios_sensor.thrs_fan_boost.temp; | 174 | return priv->bios_sensor.thrs_fan_boost.temp; |
47 | case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST: | 175 | case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST: |
@@ -73,42 +201,50 @@ nouveau_therm_attr_set(struct nouveau_therm *therm, | |||
73 | case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY: | 201 | case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY: |
74 | if (value < 0) | 202 | if (value < 0) |
75 | value = 0; | 203 | value = 0; |
76 | if (value > priv->bios_fan.max_duty) | 204 | if (value > priv->fan->bios.max_duty) |
77 | value = priv->bios_fan.max_duty; | 205 | value = priv->fan->bios.max_duty; |
78 | priv->bios_fan.min_duty = value; | 206 | priv->fan->bios.min_duty = value; |
79 | return 0; | 207 | return 0; |
80 | case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY: | 208 | case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY: |
81 | if (value < 0) | 209 | if (value < 0) |
82 | value = 0; | 210 | value = 0; |
83 | if (value < priv->bios_fan.min_duty) | 211 | if (value < priv->fan->bios.min_duty) |
84 | value = priv->bios_fan.min_duty; | 212 | value = priv->fan->bios.min_duty; |
85 | priv->bios_fan.max_duty = value; | 213 | priv->fan->bios.max_duty = value; |
86 | return 0; | 214 | return 0; |
87 | case NOUVEAU_THERM_ATTR_FAN_MODE: | 215 | case NOUVEAU_THERM_ATTR_FAN_MODE: |
88 | return nouveau_therm_fan_set_mode(therm, value); | 216 | return nouveau_therm_mode(therm, value); |
89 | case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: | 217 | case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: |
90 | priv->bios_sensor.thrs_fan_boost.temp = value; | 218 | priv->bios_sensor.thrs_fan_boost.temp = value; |
219 | priv->sensor.program_alarms(therm); | ||
91 | return 0; | 220 | return 0; |
92 | case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST: | 221 | case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST: |
93 | priv->bios_sensor.thrs_fan_boost.hysteresis = value; | 222 | priv->bios_sensor.thrs_fan_boost.hysteresis = value; |
223 | priv->sensor.program_alarms(therm); | ||
94 | return 0; | 224 | return 0; |
95 | case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK: | 225 | case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK: |
96 | priv->bios_sensor.thrs_down_clock.temp = value; | 226 | priv->bios_sensor.thrs_down_clock.temp = value; |
227 | priv->sensor.program_alarms(therm); | ||
97 | return 0; | 228 | return 0; |
98 | case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST: | 229 | case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST: |
99 | priv->bios_sensor.thrs_down_clock.hysteresis = value; | 230 | priv->bios_sensor.thrs_down_clock.hysteresis = value; |
231 | priv->sensor.program_alarms(therm); | ||
100 | return 0; | 232 | return 0; |
101 | case NOUVEAU_THERM_ATTR_THRS_CRITICAL: | 233 | case NOUVEAU_THERM_ATTR_THRS_CRITICAL: |
102 | priv->bios_sensor.thrs_critical.temp = value; | 234 | priv->bios_sensor.thrs_critical.temp = value; |
235 | priv->sensor.program_alarms(therm); | ||
103 | return 0; | 236 | return 0; |
104 | case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST: | 237 | case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST: |
105 | priv->bios_sensor.thrs_critical.hysteresis = value; | 238 | priv->bios_sensor.thrs_critical.hysteresis = value; |
239 | priv->sensor.program_alarms(therm); | ||
106 | return 0; | 240 | return 0; |
107 | case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN: | 241 | case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN: |
108 | priv->bios_sensor.thrs_shutdown.temp = value; | 242 | priv->bios_sensor.thrs_shutdown.temp = value; |
243 | priv->sensor.program_alarms(therm); | ||
109 | return 0; | 244 | return 0; |
110 | case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST: | 245 | case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST: |
111 | priv->bios_sensor.thrs_shutdown.hysteresis = value; | 246 | priv->bios_sensor.thrs_shutdown.hysteresis = value; |
247 | priv->sensor.program_alarms(therm); | ||
112 | return 0; | 248 | return 0; |
113 | } | 249 | } |
114 | 250 | ||
@@ -116,7 +252,7 @@ nouveau_therm_attr_set(struct nouveau_therm *therm, | |||
116 | } | 252 | } |
117 | 253 | ||
118 | int | 254 | int |
119 | nouveau_therm_init(struct nouveau_object *object) | 255 | _nouveau_therm_init(struct nouveau_object *object) |
120 | { | 256 | { |
121 | struct nouveau_therm *therm = (void *)object; | 257 | struct nouveau_therm *therm = (void *)object; |
122 | struct nouveau_therm_priv *priv = (void *)therm; | 258 | struct nouveau_therm_priv *priv = (void *)therm; |
@@ -126,19 +262,69 @@ nouveau_therm_init(struct nouveau_object *object) | |||
126 | if (ret) | 262 | if (ret) |
127 | return ret; | 263 | return ret; |
128 | 264 | ||
129 | if (priv->fan.percent >= 0) | 265 | if (priv->suspend >= 0) |
130 | therm->fan_set(therm, priv->fan.percent); | 266 | nouveau_therm_mode(therm, priv->mode); |
131 | 267 | priv->sensor.program_alarms(therm); | |
132 | return 0; | 268 | return 0; |
133 | } | 269 | } |
134 | 270 | ||
135 | int | 271 | int |
136 | nouveau_therm_fini(struct nouveau_object *object, bool suspend) | 272 | _nouveau_therm_fini(struct nouveau_object *object, bool suspend) |
137 | { | 273 | { |
138 | struct nouveau_therm *therm = (void *)object; | 274 | struct nouveau_therm *therm = (void *)object; |
139 | struct nouveau_therm_priv *priv = (void *)therm; | 275 | struct nouveau_therm_priv *priv = (void *)therm; |
140 | 276 | ||
141 | priv->fan.percent = therm->fan_get(therm); | 277 | if (suspend) { |
278 | priv->suspend = priv->mode; | ||
279 | priv->mode = NOUVEAU_THERM_CTRL_NONE; | ||
280 | } | ||
142 | 281 | ||
143 | return nouveau_subdev_fini(&therm->base, suspend); | 282 | return nouveau_subdev_fini(&therm->base, suspend); |
144 | } | 283 | } |
284 | |||
285 | int | ||
286 | nouveau_therm_create_(struct nouveau_object *parent, | ||
287 | struct nouveau_object *engine, | ||
288 | struct nouveau_oclass *oclass, | ||
289 | int length, void **pobject) | ||
290 | { | ||
291 | struct nouveau_therm_priv *priv; | ||
292 | int ret; | ||
293 | |||
294 | ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PTHERM", | ||
295 | "therm", length, pobject); | ||
296 | priv = *pobject; | ||
297 | if (ret) | ||
298 | return ret; | ||
299 | |||
300 | nouveau_alarm_init(&priv->alarm, nouveau_therm_alarm); | ||
301 | spin_lock_init(&priv->lock); | ||
302 | spin_lock_init(&priv->sensor.alarm_program_lock); | ||
303 | |||
304 | priv->base.fan_get = nouveau_therm_fan_user_get; | ||
305 | priv->base.fan_set = nouveau_therm_fan_user_set; | ||
306 | priv->base.fan_sense = nouveau_therm_fan_sense; | ||
307 | priv->base.attr_get = nouveau_therm_attr_get; | ||
308 | priv->base.attr_set = nouveau_therm_attr_set; | ||
309 | priv->mode = priv->suspend = -1; /* undefined */ | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | int | ||
314 | nouveau_therm_preinit(struct nouveau_therm *therm) | ||
315 | { | ||
316 | nouveau_therm_ic_ctor(therm); | ||
317 | nouveau_therm_sensor_ctor(therm); | ||
318 | nouveau_therm_fan_ctor(therm); | ||
319 | |||
320 | nouveau_therm_mode(therm, NOUVEAU_THERM_CTRL_NONE); | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | void | ||
325 | _nouveau_therm_dtor(struct nouveau_object *object) | ||
326 | { | ||
327 | struct nouveau_therm_priv *priv = (void *)object; | ||
328 | kfree(priv->fan); | ||
329 | nouveau_subdev_destroy(&priv->base.base); | ||
330 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c index 523178685180..c728380d3d62 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c | |||
@@ -27,90 +27,107 @@ | |||
27 | 27 | ||
28 | #include <core/object.h> | 28 | #include <core/object.h> |
29 | #include <core/device.h> | 29 | #include <core/device.h> |
30 | |||
30 | #include <subdev/gpio.h> | 31 | #include <subdev/gpio.h> |
31 | #include <subdev/timer.h> | 32 | #include <subdev/timer.h> |
32 | 33 | ||
33 | int | 34 | static int |
34 | nouveau_therm_fan_get(struct nouveau_therm *therm) | 35 | nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target) |
35 | { | 36 | { |
37 | struct nouveau_therm *therm = fan->parent; | ||
36 | struct nouveau_therm_priv *priv = (void *)therm; | 38 | struct nouveau_therm_priv *priv = (void *)therm; |
37 | struct nouveau_gpio *gpio = nouveau_gpio(therm); | 39 | struct nouveau_timer *ptimer = nouveau_timer(priv); |
38 | struct dcb_gpio_func func; | 40 | unsigned long flags; |
39 | int card_type = nv_device(therm)->card_type; | 41 | int ret = 0; |
40 | u32 divs, duty; | 42 | int duty; |
41 | int ret; | 43 | |
42 | 44 | /* update target fan speed, restricting to allowed range */ | |
43 | if (!priv->fan.pwm_get) | 45 | spin_lock_irqsave(&fan->lock, flags); |
44 | return -ENODEV; | 46 | if (target < 0) |
47 | target = fan->percent; | ||
48 | target = max_t(u8, target, fan->bios.min_duty); | ||
49 | target = min_t(u8, target, fan->bios.max_duty); | ||
50 | if (fan->percent != target) { | ||
51 | nv_debug(therm, "FAN target: %d\n", target); | ||
52 | fan->percent = target; | ||
53 | } | ||
45 | 54 | ||
46 | ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func); | 55 | /* check that we're not already at the target duty cycle */ |
47 | if (ret == 0) { | 56 | duty = fan->get(therm); |
48 | ret = priv->fan.pwm_get(therm, func.line, &divs, &duty); | 57 | if (duty == target) |
49 | if (ret == 0 && divs) { | 58 | goto done; |
50 | divs = max(divs, duty); | 59 | |
51 | if (card_type <= NV_40 || (func.log[0] & 1)) | 60 | /* smooth out the fanspeed increase/decrease */ |
52 | duty = divs - duty; | 61 | if (!immediate && duty >= 0) { |
53 | return (duty * 100) / divs; | 62 | /* the constant "3" is a rough approximation taken from |
54 | } | 63 | * nvidia's behaviour. |
64 | * it is meant to bump the fan speed more incrementally | ||
65 | */ | ||
66 | if (duty < target) | ||
67 | duty = min(duty + 3, target); | ||
68 | else if (duty > target) | ||
69 | duty = max(duty - 3, target); | ||
70 | } else { | ||
71 | duty = target; | ||
72 | } | ||
55 | 73 | ||
56 | return gpio->get(gpio, 0, func.func, func.line) * 100; | 74 | nv_debug(therm, "FAN update: %d\n", duty); |
75 | ret = fan->set(therm, duty); | ||
76 | if (ret) | ||
77 | goto done; | ||
78 | |||
79 | /* schedule next fan update, if not at target speed already */ | ||
80 | if (list_empty(&fan->alarm.head) && target != duty) { | ||
81 | u16 bump_period = fan->bios.bump_period; | ||
82 | u16 slow_down_period = fan->bios.slow_down_period; | ||
83 | u64 delay; | ||
84 | |||
85 | if (duty > target) | ||
86 | delay = slow_down_period; | ||
87 | else if (duty == target) | ||
88 | delay = min(bump_period, slow_down_period) ; | ||
89 | else | ||
90 | delay = bump_period; | ||
91 | |||
92 | ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm); | ||
57 | } | 93 | } |
58 | 94 | ||
59 | return -ENODEV; | 95 | done: |
96 | spin_unlock_irqrestore(&fan->lock, flags); | ||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | static void | ||
101 | nouveau_fan_alarm(struct nouveau_alarm *alarm) | ||
102 | { | ||
103 | struct nouveau_fan *fan = container_of(alarm, struct nouveau_fan, alarm); | ||
104 | nouveau_fan_update(fan, false, -1); | ||
60 | } | 105 | } |
61 | 106 | ||
62 | int | 107 | int |
63 | nouveau_therm_fan_set(struct nouveau_therm *therm, int percent) | 108 | nouveau_therm_fan_get(struct nouveau_therm *therm) |
64 | { | 109 | { |
65 | struct nouveau_therm_priv *priv = (void *)therm; | 110 | struct nouveau_therm_priv *priv = (void *)therm; |
66 | struct nouveau_gpio *gpio = nouveau_gpio(therm); | 111 | return priv->fan->get(therm); |
67 | struct dcb_gpio_func func; | 112 | } |
68 | int card_type = nv_device(therm)->card_type; | ||
69 | u32 divs, duty; | ||
70 | int ret; | ||
71 | |||
72 | if (priv->fan.mode == FAN_CONTROL_NONE) | ||
73 | return -EINVAL; | ||
74 | |||
75 | if (!priv->fan.pwm_set) | ||
76 | return -ENODEV; | ||
77 | |||
78 | if (percent < priv->bios_fan.min_duty) | ||
79 | percent = priv->bios_fan.min_duty; | ||
80 | if (percent > priv->bios_fan.max_duty) | ||
81 | percent = priv->bios_fan.max_duty; | ||
82 | |||
83 | ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func); | ||
84 | if (ret == 0) { | ||
85 | divs = priv->bios_perf_fan.pwm_divisor; | ||
86 | if (priv->bios_fan.pwm_freq) { | ||
87 | divs = 1; | ||
88 | if (priv->fan.pwm_clock) | ||
89 | divs = priv->fan.pwm_clock(therm); | ||
90 | divs /= priv->bios_fan.pwm_freq; | ||
91 | } | ||
92 | |||
93 | duty = ((divs * percent) + 99) / 100; | ||
94 | if (card_type <= NV_40 || (func.log[0] & 1)) | ||
95 | duty = divs - duty; | ||
96 | |||
97 | ret = priv->fan.pwm_set(therm, func.line, divs, duty); | ||
98 | return ret; | ||
99 | } | ||
100 | 113 | ||
101 | return -ENODEV; | 114 | int |
115 | nouveau_therm_fan_set(struct nouveau_therm *therm, bool immediate, int percent) | ||
116 | { | ||
117 | struct nouveau_therm_priv *priv = (void *)therm; | ||
118 | return nouveau_fan_update(priv->fan, immediate, percent); | ||
102 | } | 119 | } |
103 | 120 | ||
104 | int | 121 | int |
105 | nouveau_therm_fan_sense(struct nouveau_therm *therm) | 122 | nouveau_therm_fan_sense(struct nouveau_therm *therm) |
106 | { | 123 | { |
124 | struct nouveau_therm_priv *priv = (void *)therm; | ||
107 | struct nouveau_timer *ptimer = nouveau_timer(therm); | 125 | struct nouveau_timer *ptimer = nouveau_timer(therm); |
108 | struct nouveau_gpio *gpio = nouveau_gpio(therm); | 126 | struct nouveau_gpio *gpio = nouveau_gpio(therm); |
109 | struct dcb_gpio_func func; | ||
110 | u32 cycles, cur, prev; | 127 | u32 cycles, cur, prev; |
111 | u64 start, end, tach; | 128 | u64 start, end, tach; |
112 | 129 | ||
113 | if (gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func)) | 130 | if (priv->fan->tach.func == DCB_GPIO_UNUSED) |
114 | return -ENODEV; | 131 | return -ENODEV; |
115 | 132 | ||
116 | /* Time a complete rotation and extrapolate to RPM: | 133 | /* Time a complete rotation and extrapolate to RPM: |
@@ -118,12 +135,12 @@ nouveau_therm_fan_sense(struct nouveau_therm *therm) | |||
118 | * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. | 135 | * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. |
119 | */ | 136 | */ |
120 | start = ptimer->read(ptimer); | 137 | start = ptimer->read(ptimer); |
121 | prev = gpio->get(gpio, 0, func.func, func.line); | 138 | prev = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line); |
122 | cycles = 0; | 139 | cycles = 0; |
123 | do { | 140 | do { |
124 | usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ | 141 | usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ |
125 | 142 | ||
126 | cur = gpio->get(gpio, 0, func.func, func.line); | 143 | cur = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line); |
127 | if (prev != cur) { | 144 | if (prev != cur) { |
128 | if (!start) | 145 | if (!start) |
129 | start = ptimer->read(ptimer); | 146 | start = ptimer->read(ptimer); |
@@ -142,34 +159,6 @@ nouveau_therm_fan_sense(struct nouveau_therm *therm) | |||
142 | } | 159 | } |
143 | 160 | ||
144 | int | 161 | int |
145 | nouveau_therm_fan_set_mode(struct nouveau_therm *therm, | ||
146 | enum nouveau_therm_fan_mode mode) | ||
147 | { | ||
148 | struct nouveau_therm_priv *priv = (void *)therm; | ||
149 | |||
150 | if (priv->fan.mode == mode) | ||
151 | return 0; | ||
152 | |||
153 | if (mode < FAN_CONTROL_NONE || mode >= FAN_CONTROL_NR) | ||
154 | return -EINVAL; | ||
155 | |||
156 | switch (mode) | ||
157 | { | ||
158 | case FAN_CONTROL_NONE: | ||
159 | nv_info(therm, "switch fan to no-control mode\n"); | ||
160 | break; | ||
161 | case FAN_CONTROL_MANUAL: | ||
162 | nv_info(therm, "switch fan to manual mode\n"); | ||
163 | break; | ||
164 | case FAN_CONTROL_NR: | ||
165 | break; | ||
166 | } | ||
167 | |||
168 | priv->fan.mode = mode; | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | int | ||
173 | nouveau_therm_fan_user_get(struct nouveau_therm *therm) | 162 | nouveau_therm_fan_user_get(struct nouveau_therm *therm) |
174 | { | 163 | { |
175 | return nouveau_therm_fan_get(therm); | 164 | return nouveau_therm_fan_get(therm); |
@@ -180,55 +169,86 @@ nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent) | |||
180 | { | 169 | { |
181 | struct nouveau_therm_priv *priv = (void *)therm; | 170 | struct nouveau_therm_priv *priv = (void *)therm; |
182 | 171 | ||
183 | if (priv->fan.mode != FAN_CONTROL_MANUAL) | 172 | if (priv->mode != NOUVEAU_THERM_CTRL_MANUAL) |
184 | return -EINVAL; | 173 | return -EINVAL; |
185 | 174 | ||
186 | return nouveau_therm_fan_set(therm, percent); | 175 | return nouveau_therm_fan_set(therm, true, percent); |
187 | } | 176 | } |
188 | 177 | ||
189 | void | 178 | static void |
190 | nouveau_therm_fan_set_defaults(struct nouveau_therm *therm) | 179 | nouveau_therm_fan_set_defaults(struct nouveau_therm *therm) |
191 | { | 180 | { |
192 | struct nouveau_therm_priv *priv = (void *)therm; | 181 | struct nouveau_therm_priv *priv = (void *)therm; |
193 | 182 | ||
194 | priv->bios_fan.pwm_freq = 0; | 183 | priv->fan->bios.pwm_freq = 0; |
195 | priv->bios_fan.min_duty = 0; | 184 | priv->fan->bios.min_duty = 0; |
196 | priv->bios_fan.max_duty = 100; | 185 | priv->fan->bios.max_duty = 100; |
186 | priv->fan->bios.bump_period = 500; | ||
187 | priv->fan->bios.slow_down_period = 2000; | ||
188 | priv->fan->bios.linear_min_temp = 40; | ||
189 | priv->fan->bios.linear_max_temp = 85; | ||
197 | } | 190 | } |
198 | 191 | ||
199 | |||
200 | static void | 192 | static void |
201 | nouveau_therm_fan_safety_checks(struct nouveau_therm *therm) | 193 | nouveau_therm_fan_safety_checks(struct nouveau_therm *therm) |
202 | { | 194 | { |
203 | struct nouveau_therm_priv *priv = (void *)therm; | 195 | struct nouveau_therm_priv *priv = (void *)therm; |
204 | 196 | ||
205 | if (priv->bios_fan.min_duty > 100) | 197 | if (priv->fan->bios.min_duty > 100) |
206 | priv->bios_fan.min_duty = 100; | 198 | priv->fan->bios.min_duty = 100; |
207 | if (priv->bios_fan.max_duty > 100) | 199 | if (priv->fan->bios.max_duty > 100) |
208 | priv->bios_fan.max_duty = 100; | 200 | priv->fan->bios.max_duty = 100; |
209 | 201 | ||
210 | if (priv->bios_fan.min_duty > priv->bios_fan.max_duty) | 202 | if (priv->fan->bios.min_duty > priv->fan->bios.max_duty) |
211 | priv->bios_fan.min_duty = priv->bios_fan.max_duty; | 203 | priv->fan->bios.min_duty = priv->fan->bios.max_duty; |
212 | } | ||
213 | |||
214 | int nouveau_fan_pwm_clock_dummy(struct nouveau_therm *therm) | ||
215 | { | ||
216 | return 1; | ||
217 | } | 204 | } |
218 | 205 | ||
219 | int | 206 | int |
220 | nouveau_therm_fan_ctor(struct nouveau_therm *therm) | 207 | nouveau_therm_fan_ctor(struct nouveau_therm *therm) |
221 | { | 208 | { |
222 | struct nouveau_therm_priv *priv = (void *)therm; | 209 | struct nouveau_therm_priv *priv = (void *)therm; |
210 | struct nouveau_gpio *gpio = nouveau_gpio(therm); | ||
223 | struct nouveau_bios *bios = nouveau_bios(therm); | 211 | struct nouveau_bios *bios = nouveau_bios(therm); |
212 | struct dcb_gpio_func func; | ||
213 | int ret; | ||
224 | 214 | ||
215 | /* attempt to locate a drivable fan, and determine control method */ | ||
216 | ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); | ||
217 | if (ret == 0) { | ||
218 | if (func.log[0] & DCB_GPIO_LOG_DIR_IN) { | ||
219 | nv_debug(therm, "GPIO_FAN is in input mode\n"); | ||
220 | ret = -EINVAL; | ||
221 | } else { | ||
222 | ret = nouveau_fanpwm_create(therm, &func); | ||
223 | if (ret != 0) | ||
224 | ret = nouveau_fantog_create(therm, &func); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | /* no controllable fan found, create a dummy fan module */ | ||
229 | if (ret != 0) { | ||
230 | ret = nouveau_fannil_create(therm); | ||
231 | if (ret) | ||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | nv_info(therm, "FAN control: %s\n", priv->fan->type); | ||
236 | |||
237 | /* attempt to detect a tachometer connection */ | ||
238 | ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach); | ||
239 | if (ret) | ||
240 | priv->fan->tach.func = DCB_GPIO_UNUSED; | ||
241 | |||
242 | /* initialise fan bump/slow update handling */ | ||
243 | priv->fan->parent = therm; | ||
244 | nouveau_alarm_init(&priv->fan->alarm, nouveau_fan_alarm); | ||
245 | spin_lock_init(&priv->fan->lock); | ||
246 | |||
247 | /* other random init... */ | ||
225 | nouveau_therm_fan_set_defaults(therm); | 248 | nouveau_therm_fan_set_defaults(therm); |
226 | nvbios_perf_fan_parse(bios, &priv->bios_perf_fan); | 249 | nvbios_perf_fan_parse(bios, &priv->fan->perf); |
227 | if (nvbios_therm_fan_parse(bios, &priv->bios_fan)) | 250 | if (nvbios_therm_fan_parse(bios, &priv->fan->bios)) |
228 | nv_error(therm, "parsing the thermal table failed\n"); | 251 | nv_error(therm, "parsing the thermal table failed\n"); |
229 | nouveau_therm_fan_safety_checks(therm); | 252 | nouveau_therm_fan_safety_checks(therm); |
230 | |||
231 | nouveau_therm_fan_set_mode(therm, FAN_CONTROL_NONE); | ||
232 | |||
233 | return 0; | 253 | return 0; |
234 | } | 254 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fannil.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fannil.c new file mode 100644 index 000000000000..b78c182e1d51 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fannil.c | |||
@@ -0,0 +1,54 @@ | |||
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 | static int | ||
28 | nouveau_fannil_get(struct nouveau_therm *therm) | ||
29 | { | ||
30 | return -ENODEV; | ||
31 | } | ||
32 | |||
33 | static int | ||
34 | nouveau_fannil_set(struct nouveau_therm *therm, int percent) | ||
35 | { | ||
36 | return -ENODEV; | ||
37 | } | ||
38 | |||
39 | int | ||
40 | nouveau_fannil_create(struct nouveau_therm *therm) | ||
41 | { | ||
42 | struct nouveau_therm_priv *tpriv = (void *)therm; | ||
43 | struct nouveau_fan *priv; | ||
44 | |||
45 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
46 | tpriv->fan = priv; | ||
47 | if (!priv) | ||
48 | return -ENOMEM; | ||
49 | |||
50 | priv->type = "none / external"; | ||
51 | priv->get = nouveau_fannil_get; | ||
52 | priv->set = nouveau_fannil_set; | ||
53 | return 0; | ||
54 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c new file mode 100644 index 000000000000..5f71db8e8992 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c | |||
@@ -0,0 +1,107 @@ | |||
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 | * Martin Peres | ||
24 | */ | ||
25 | |||
26 | #include <core/option.h> | ||
27 | #include <subdev/gpio.h> | ||
28 | |||
29 | #include "priv.h" | ||
30 | |||
31 | struct nouveau_fanpwm_priv { | ||
32 | struct nouveau_fan base; | ||
33 | struct dcb_gpio_func func; | ||
34 | }; | ||
35 | |||
36 | static int | ||
37 | nouveau_fanpwm_get(struct nouveau_therm *therm) | ||
38 | { | ||
39 | struct nouveau_therm_priv *tpriv = (void *)therm; | ||
40 | struct nouveau_fanpwm_priv *priv = (void *)tpriv->fan; | ||
41 | struct nouveau_gpio *gpio = nouveau_gpio(therm); | ||
42 | int card_type = nv_device(therm)->card_type; | ||
43 | u32 divs, duty; | ||
44 | int ret; | ||
45 | |||
46 | ret = therm->pwm_get(therm, priv->func.line, &divs, &duty); | ||
47 | if (ret == 0 && divs) { | ||
48 | divs = max(divs, duty); | ||
49 | if (card_type <= NV_40 || (priv->func.log[0] & 1)) | ||
50 | duty = divs - duty; | ||
51 | return (duty * 100) / divs; | ||
52 | } | ||
53 | |||
54 | return gpio->get(gpio, 0, priv->func.func, priv->func.line) * 100; | ||
55 | } | ||
56 | |||
57 | static int | ||
58 | nouveau_fanpwm_set(struct nouveau_therm *therm, int percent) | ||
59 | { | ||
60 | struct nouveau_therm_priv *tpriv = (void *)therm; | ||
61 | struct nouveau_fanpwm_priv *priv = (void *)tpriv->fan; | ||
62 | int card_type = nv_device(therm)->card_type; | ||
63 | u32 divs, duty; | ||
64 | int ret; | ||
65 | |||
66 | divs = priv->base.perf.pwm_divisor; | ||
67 | if (priv->base.bios.pwm_freq) { | ||
68 | divs = 1; | ||
69 | if (therm->pwm_clock) | ||
70 | divs = therm->pwm_clock(therm); | ||
71 | divs /= priv->base.bios.pwm_freq; | ||
72 | } | ||
73 | |||
74 | duty = ((divs * percent) + 99) / 100; | ||
75 | if (card_type <= NV_40 || (priv->func.log[0] & 1)) | ||
76 | duty = divs - duty; | ||
77 | |||
78 | ret = therm->pwm_set(therm, priv->func.line, divs, duty); | ||
79 | if (ret == 0) | ||
80 | ret = therm->pwm_ctrl(therm, priv->func.line, true); | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | int | ||
85 | nouveau_fanpwm_create(struct nouveau_therm *therm, struct dcb_gpio_func *func) | ||
86 | { | ||
87 | struct nouveau_device *device = nv_device(therm); | ||
88 | struct nouveau_therm_priv *tpriv = (void *)therm; | ||
89 | struct nouveau_fanpwm_priv *priv; | ||
90 | u32 divs, duty; | ||
91 | |||
92 | if (!nouveau_boolopt(device->cfgopt, "NvFanPWM", func->param) || | ||
93 | !therm->pwm_ctrl || | ||
94 | therm->pwm_get(therm, func->line, &divs, &duty) == -ENODEV) | ||
95 | return -ENODEV; | ||
96 | |||
97 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
98 | tpriv->fan = &priv->base; | ||
99 | if (!priv) | ||
100 | return -ENOMEM; | ||
101 | |||
102 | priv->base.type = "PWM"; | ||
103 | priv->base.get = nouveau_fanpwm_get; | ||
104 | priv->base.set = nouveau_fanpwm_set; | ||
105 | priv->func = *func; | ||
106 | return 0; | ||
107 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c new file mode 100644 index 000000000000..e601773ee475 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * Copyright 2012 The Nouveau community | ||
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: Martin Peres | ||
23 | */ | ||
24 | |||
25 | #include "priv.h" | ||
26 | |||
27 | #include <core/object.h> | ||
28 | #include <core/device.h> | ||
29 | |||
30 | #include <subdev/gpio.h> | ||
31 | #include <subdev/timer.h> | ||
32 | |||
33 | struct nouveau_fantog_priv { | ||
34 | struct nouveau_fan base; | ||
35 | struct nouveau_alarm alarm; | ||
36 | spinlock_t lock; | ||
37 | u32 period_us; | ||
38 | u32 percent; | ||
39 | struct dcb_gpio_func func; | ||
40 | }; | ||
41 | |||
42 | static void | ||
43 | nouveau_fantog_update(struct nouveau_fantog_priv *priv, int percent) | ||
44 | { | ||
45 | struct nouveau_therm_priv *tpriv = (void *)priv->base.parent; | ||
46 | struct nouveau_timer *ptimer = nouveau_timer(tpriv); | ||
47 | struct nouveau_gpio *gpio = nouveau_gpio(tpriv); | ||
48 | unsigned long flags; | ||
49 | int duty; | ||
50 | |||
51 | spin_lock_irqsave(&priv->lock, flags); | ||
52 | if (percent < 0) | ||
53 | percent = priv->percent; | ||
54 | priv->percent = percent; | ||
55 | |||
56 | duty = !gpio->get(gpio, 0, DCB_GPIO_FAN, 0xff); | ||
57 | gpio->set(gpio, 0, DCB_GPIO_FAN, 0xff, duty); | ||
58 | |||
59 | if (list_empty(&priv->alarm.head) && percent != (duty * 100)) { | ||
60 | u64 next_change = (percent * priv->period_us) / 100; | ||
61 | if (!duty) | ||
62 | next_change = priv->period_us - next_change; | ||
63 | ptimer->alarm(ptimer, next_change * 1000, &priv->alarm); | ||
64 | } | ||
65 | spin_unlock_irqrestore(&priv->lock, flags); | ||
66 | } | ||
67 | |||
68 | static void | ||
69 | nouveau_fantog_alarm(struct nouveau_alarm *alarm) | ||
70 | { | ||
71 | struct nouveau_fantog_priv *priv = | ||
72 | container_of(alarm, struct nouveau_fantog_priv, alarm); | ||
73 | nouveau_fantog_update(priv, -1); | ||
74 | } | ||
75 | |||
76 | static int | ||
77 | nouveau_fantog_get(struct nouveau_therm *therm) | ||
78 | { | ||
79 | struct nouveau_therm_priv *tpriv = (void *)therm; | ||
80 | struct nouveau_fantog_priv *priv = (void *)tpriv->fan; | ||
81 | return priv->percent; | ||
82 | } | ||
83 | |||
84 | static int | ||
85 | nouveau_fantog_set(struct nouveau_therm *therm, int percent) | ||
86 | { | ||
87 | struct nouveau_therm_priv *tpriv = (void *)therm; | ||
88 | struct nouveau_fantog_priv *priv = (void *)tpriv->fan; | ||
89 | if (therm->pwm_ctrl) | ||
90 | therm->pwm_ctrl(therm, priv->func.line, false); | ||
91 | nouveau_fantog_update(priv, percent); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | int | ||
96 | nouveau_fantog_create(struct nouveau_therm *therm, struct dcb_gpio_func *func) | ||
97 | { | ||
98 | struct nouveau_therm_priv *tpriv = (void *)therm; | ||
99 | struct nouveau_fantog_priv *priv; | ||
100 | |||
101 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
102 | tpriv->fan = &priv->base; | ||
103 | if (!priv) | ||
104 | return -ENOMEM; | ||
105 | |||
106 | priv->base.type = "toggle"; | ||
107 | priv->base.get = nouveau_fantog_get; | ||
108 | priv->base.set = nouveau_fantog_set; | ||
109 | nouveau_alarm_init(&priv->alarm, nouveau_fantog_alarm); | ||
110 | priv->period_us = 100000; /* 10Hz */ | ||
111 | priv->percent = 100; | ||
112 | priv->func = *func; | ||
113 | spin_lock_init(&priv->lock); | ||
114 | return 0; | ||
115 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c index e512ff0aae60..e24090bac195 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c | |||
@@ -31,7 +31,7 @@ static bool | |||
31 | probe_monitoring_device(struct nouveau_i2c_port *i2c, | 31 | probe_monitoring_device(struct nouveau_i2c_port *i2c, |
32 | struct i2c_board_info *info) | 32 | struct i2c_board_info *info) |
33 | { | 33 | { |
34 | struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c->i2c); | 34 | struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c); |
35 | struct i2c_client *client; | 35 | struct i2c_client *client; |
36 | 36 | ||
37 | request_module("%s%s", I2C_MODULE_PREFIX, info->type); | 37 | request_module("%s%s", I2C_MODULE_PREFIX, info->type); |
@@ -53,6 +53,31 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c, | |||
53 | return true; | 53 | return true; |
54 | } | 54 | } |
55 | 55 | ||
56 | static struct i2c_board_info | ||
57 | nv_board_infos[] = { | ||
58 | { I2C_BOARD_INFO("w83l785ts", 0x2d) }, | ||
59 | { I2C_BOARD_INFO("w83781d", 0x2d) }, | ||
60 | { I2C_BOARD_INFO("adt7473", 0x2e) }, | ||
61 | { I2C_BOARD_INFO("adt7473", 0x2d) }, | ||
62 | { I2C_BOARD_INFO("adt7473", 0x2c) }, | ||
63 | { I2C_BOARD_INFO("f75375", 0x2e) }, | ||
64 | { I2C_BOARD_INFO("lm99", 0x4c) }, | ||
65 | { I2C_BOARD_INFO("lm90", 0x4c) }, | ||
66 | { I2C_BOARD_INFO("lm90", 0x4d) }, | ||
67 | { I2C_BOARD_INFO("adm1021", 0x18) }, | ||
68 | { I2C_BOARD_INFO("adm1021", 0x19) }, | ||
69 | { I2C_BOARD_INFO("adm1021", 0x1a) }, | ||
70 | { I2C_BOARD_INFO("adm1021", 0x29) }, | ||
71 | { I2C_BOARD_INFO("adm1021", 0x2a) }, | ||
72 | { I2C_BOARD_INFO("adm1021", 0x2b) }, | ||
73 | { I2C_BOARD_INFO("adm1021", 0x4c) }, | ||
74 | { I2C_BOARD_INFO("adm1021", 0x4d) }, | ||
75 | { I2C_BOARD_INFO("adm1021", 0x4e) }, | ||
76 | { I2C_BOARD_INFO("lm63", 0x18) }, | ||
77 | { I2C_BOARD_INFO("lm63", 0x4e) }, | ||
78 | { } | ||
79 | }; | ||
80 | |||
56 | void | 81 | void |
57 | nouveau_therm_ic_ctor(struct nouveau_therm *therm) | 82 | nouveau_therm_ic_ctor(struct nouveau_therm *therm) |
58 | { | 83 | { |
@@ -60,29 +85,6 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm) | |||
60 | struct nouveau_bios *bios = nouveau_bios(therm); | 85 | struct nouveau_bios *bios = nouveau_bios(therm); |
61 | struct nouveau_i2c *i2c = nouveau_i2c(therm); | 86 | struct nouveau_i2c *i2c = nouveau_i2c(therm); |
62 | struct nvbios_extdev_func extdev_entry; | 87 | struct nvbios_extdev_func extdev_entry; |
63 | struct i2c_board_info info[] = { | ||
64 | { I2C_BOARD_INFO("w83l785ts", 0x2d) }, | ||
65 | { I2C_BOARD_INFO("w83781d", 0x2d) }, | ||
66 | { I2C_BOARD_INFO("adt7473", 0x2e) }, | ||
67 | { I2C_BOARD_INFO("adt7473", 0x2d) }, | ||
68 | { I2C_BOARD_INFO("adt7473", 0x2c) }, | ||
69 | { I2C_BOARD_INFO("f75375", 0x2e) }, | ||
70 | { I2C_BOARD_INFO("lm99", 0x4c) }, | ||
71 | { I2C_BOARD_INFO("lm90", 0x4c) }, | ||
72 | { I2C_BOARD_INFO("lm90", 0x4d) }, | ||
73 | { I2C_BOARD_INFO("adm1021", 0x18) }, | ||
74 | { I2C_BOARD_INFO("adm1021", 0x19) }, | ||
75 | { I2C_BOARD_INFO("adm1021", 0x1a) }, | ||
76 | { I2C_BOARD_INFO("adm1021", 0x29) }, | ||
77 | { I2C_BOARD_INFO("adm1021", 0x2a) }, | ||
78 | { I2C_BOARD_INFO("adm1021", 0x2b) }, | ||
79 | { I2C_BOARD_INFO("adm1021", 0x4c) }, | ||
80 | { I2C_BOARD_INFO("adm1021", 0x4d) }, | ||
81 | { I2C_BOARD_INFO("adm1021", 0x4e) }, | ||
82 | { I2C_BOARD_INFO("lm63", 0x18) }, | ||
83 | { I2C_BOARD_INFO("lm63", 0x4e) }, | ||
84 | { } | ||
85 | }; | ||
86 | 88 | ||
87 | if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) { | 89 | if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) { |
88 | struct i2c_board_info board[] = { | 90 | struct i2c_board_info board[] = { |
@@ -111,6 +113,6 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm) | |||
111 | /* The vbios doesn't provide the address of an exisiting monitoring | 113 | /* The vbios doesn't provide the address of an exisiting monitoring |
112 | device. Let's try our static list. | 114 | device. Let's try our static list. |
113 | */ | 115 | */ |
114 | i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", info, | 116 | i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", |
115 | probe_monitoring_device); | 117 | nv_board_infos, probe_monitoring_device); |
116 | } | 118 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c index fcf2cfe731d6..0f5363edb964 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c | |||
@@ -25,6 +25,10 @@ | |||
25 | 25 | ||
26 | #include "priv.h" | 26 | #include "priv.h" |
27 | 27 | ||
28 | struct nv40_therm_priv { | ||
29 | struct nouveau_therm_priv base; | ||
30 | }; | ||
31 | |||
28 | static int | 32 | static int |
29 | nv40_sensor_setup(struct nouveau_therm *therm) | 33 | nv40_sensor_setup(struct nouveau_therm *therm) |
30 | { | 34 | { |
@@ -34,6 +38,7 @@ nv40_sensor_setup(struct nouveau_therm *therm) | |||
34 | if (device->chipset >= 0x46) { | 38 | if (device->chipset >= 0x46) { |
35 | nv_mask(therm, 0x15b8, 0x80000000, 0); | 39 | nv_mask(therm, 0x15b8, 0x80000000, 0); |
36 | nv_wr32(therm, 0x15b0, 0x80003fff); | 40 | nv_wr32(therm, 0x15b0, 0x80003fff); |
41 | mdelay(10); /* wait for the temperature to stabilize */ | ||
37 | return nv_rd32(therm, 0x15b4) & 0x3fff; | 42 | return nv_rd32(therm, 0x15b4) & 0x3fff; |
38 | } else { | 43 | } else { |
39 | nv_wr32(therm, 0x15b0, 0xff); | 44 | nv_wr32(therm, 0x15b0, 0xff); |
@@ -75,7 +80,20 @@ nv40_temp_get(struct nouveau_therm *therm) | |||
75 | return core_temp; | 80 | return core_temp; |
76 | } | 81 | } |
77 | 82 | ||
78 | int | 83 | static int |
84 | nv40_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) | ||
85 | { | ||
86 | u32 mask = enable ? 0x80000000 : 0x0000000; | ||
87 | if (line == 2) nv_mask(therm, 0x0010f0, 0x80000000, mask); | ||
88 | else if (line == 9) nv_mask(therm, 0x0015f4, 0x80000000, mask); | ||
89 | else { | ||
90 | nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); | ||
91 | return -ENODEV; | ||
92 | } | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int | ||
79 | nv40_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) | 97 | nv40_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) |
80 | { | 98 | { |
81 | if (line == 2) { | 99 | if (line == 2) { |
@@ -101,15 +119,15 @@ nv40_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) | |||
101 | return -EINVAL; | 119 | return -EINVAL; |
102 | } | 120 | } |
103 | 121 | ||
104 | int | 122 | static int |
105 | nv40_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) | 123 | nv40_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) |
106 | { | 124 | { |
107 | if (line == 2) { | 125 | if (line == 2) { |
108 | nv_wr32(therm, 0x0010f0, 0x80000000 | (duty << 16) | divs); | 126 | nv_mask(therm, 0x0010f0, 0x7fff7fff, (duty << 16) | divs); |
109 | } else | 127 | } else |
110 | if (line == 9) { | 128 | if (line == 9) { |
111 | nv_wr32(therm, 0x0015f8, divs); | 129 | nv_wr32(therm, 0x0015f8, divs); |
112 | nv_wr32(therm, 0x0015f4, duty | 0x80000000); | 130 | nv_mask(therm, 0x0015f4, 0x7fffffff, duty); |
113 | } else { | 131 | } else { |
114 | nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); | 132 | nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); |
115 | return -ENODEV; | 133 | return -ENODEV; |
@@ -118,37 +136,51 @@ nv40_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) | |||
118 | return 0; | 136 | return 0; |
119 | } | 137 | } |
120 | 138 | ||
139 | static void | ||
140 | nv40_therm_intr(struct nouveau_subdev *subdev) | ||
141 | { | ||
142 | struct nouveau_therm *therm = nouveau_therm(subdev); | ||
143 | uint32_t stat = nv_rd32(therm, 0x1100); | ||
144 | |||
145 | /* traitement */ | ||
146 | |||
147 | /* ack all IRQs */ | ||
148 | nv_wr32(therm, 0x1100, 0x70000); | ||
149 | |||
150 | nv_error(therm, "THERM received an IRQ: stat = %x\n", stat); | ||
151 | } | ||
152 | |||
121 | static int | 153 | static int |
122 | nv40_therm_ctor(struct nouveau_object *parent, | 154 | nv40_therm_ctor(struct nouveau_object *parent, |
123 | struct nouveau_object *engine, | 155 | struct nouveau_object *engine, |
124 | struct nouveau_oclass *oclass, void *data, u32 size, | 156 | struct nouveau_oclass *oclass, void *data, u32 size, |
125 | struct nouveau_object **pobject) | 157 | struct nouveau_object **pobject) |
126 | { | 158 | { |
127 | struct nouveau_therm_priv *priv; | 159 | struct nv40_therm_priv *priv; |
128 | struct nouveau_therm *therm; | ||
129 | int ret; | 160 | int ret; |
130 | 161 | ||
131 | ret = nouveau_therm_create(parent, engine, oclass, &priv); | 162 | ret = nouveau_therm_create(parent, engine, oclass, &priv); |
132 | *pobject = nv_object(priv); | 163 | *pobject = nv_object(priv); |
133 | therm = (void *) priv; | ||
134 | if (ret) | 164 | if (ret) |
135 | return ret; | 165 | return ret; |
136 | 166 | ||
137 | nouveau_therm_ic_ctor(therm); | 167 | priv->base.base.pwm_ctrl = nv40_fan_pwm_ctrl; |
138 | nouveau_therm_sensor_ctor(therm); | 168 | priv->base.base.pwm_get = nv40_fan_pwm_get; |
139 | nouveau_therm_fan_ctor(therm); | 169 | priv->base.base.pwm_set = nv40_fan_pwm_set; |
170 | priv->base.base.temp_get = nv40_temp_get; | ||
171 | priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling; | ||
172 | nv_subdev(priv)->intr = nv40_therm_intr; | ||
173 | return nouveau_therm_preinit(&priv->base.base); | ||
174 | } | ||
140 | 175 | ||
141 | priv->fan.pwm_get = nv40_fan_pwm_get; | 176 | static int |
142 | priv->fan.pwm_set = nv40_fan_pwm_set; | 177 | nv40_therm_init(struct nouveau_object *object) |
178 | { | ||
179 | struct nouveau_therm *therm = (void *)object; | ||
143 | 180 | ||
144 | therm->temp_get = nv40_temp_get; | 181 | nv40_sensor_setup(therm); |
145 | therm->fan_get = nouveau_therm_fan_user_get; | ||
146 | therm->fan_set = nouveau_therm_fan_user_set; | ||
147 | therm->fan_sense = nouveau_therm_fan_sense; | ||
148 | therm->attr_get = nouveau_therm_attr_get; | ||
149 | therm->attr_set = nouveau_therm_attr_set; | ||
150 | 182 | ||
151 | return 0; | 183 | return _nouveau_therm_init(object); |
152 | } | 184 | } |
153 | 185 | ||
154 | struct nouveau_oclass | 186 | struct nouveau_oclass |
@@ -157,7 +189,7 @@ nv40_therm_oclass = { | |||
157 | .ofuncs = &(struct nouveau_ofuncs) { | 189 | .ofuncs = &(struct nouveau_ofuncs) { |
158 | .ctor = nv40_therm_ctor, | 190 | .ctor = nv40_therm_ctor, |
159 | .dtor = _nouveau_therm_dtor, | 191 | .dtor = _nouveau_therm_dtor, |
160 | .init = nouveau_therm_init, | 192 | .init = nv40_therm_init, |
161 | .fini = nouveau_therm_fini, | 193 | .fini = _nouveau_therm_fini, |
162 | }, | 194 | }, |
163 | }; \ No newline at end of file | 195 | }; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c index 9360ddd469e7..86632cbd65ce 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c | |||
@@ -25,6 +25,10 @@ | |||
25 | 25 | ||
26 | #include "priv.h" | 26 | #include "priv.h" |
27 | 27 | ||
28 | struct nv50_therm_priv { | ||
29 | struct nouveau_therm_priv base; | ||
30 | }; | ||
31 | |||
28 | static int | 32 | static int |
29 | pwm_info(struct nouveau_therm *therm, int *line, int *ctrl, int *indx) | 33 | pwm_info(struct nouveau_therm *therm, int *line, int *ctrl, int *indx) |
30 | { | 34 | { |
@@ -51,6 +55,16 @@ pwm_info(struct nouveau_therm *therm, int *line, int *ctrl, int *indx) | |||
51 | } | 55 | } |
52 | 56 | ||
53 | int | 57 | int |
58 | nv50_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) | ||
59 | { | ||
60 | u32 data = enable ? 0x00000001 : 0x00000000; | ||
61 | int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); | ||
62 | if (ret == 0) | ||
63 | nv_mask(therm, ctrl, 0x00010001 << line, data << line); | ||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | int | ||
54 | nv50_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) | 68 | nv50_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) |
55 | { | 69 | { |
56 | int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); | 70 | int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); |
@@ -73,7 +87,6 @@ nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) | |||
73 | if (ret) | 87 | if (ret) |
74 | return ret; | 88 | return ret; |
75 | 89 | ||
76 | nv_mask(therm, ctrl, 0x00010001 << line, 0x00000001 << line); | ||
77 | nv_wr32(therm, 0x00e114 + (id * 8), divs); | 90 | nv_wr32(therm, 0x00e114 + (id * 8), divs); |
78 | nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000); | 91 | nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000); |
79 | return 0; | 92 | return 0; |
@@ -111,38 +124,178 @@ nv50_temp_get(struct nouveau_therm *therm) | |||
111 | return nv_rd32(therm, 0x20400); | 124 | return nv_rd32(therm, 0x20400); |
112 | } | 125 | } |
113 | 126 | ||
127 | static void | ||
128 | nv50_therm_program_alarms(struct nouveau_therm *therm) | ||
129 | { | ||
130 | struct nouveau_therm_priv *priv = (void *)therm; | ||
131 | struct nvbios_therm_sensor *sensor = &priv->bios_sensor; | ||
132 | unsigned long flags; | ||
133 | |||
134 | spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); | ||
135 | |||
136 | /* enable RISING and FALLING IRQs for shutdown, THRS 0, 1, 2 and 4 */ | ||
137 | nv_wr32(therm, 0x20000, 0x000003ff); | ||
138 | |||
139 | /* shutdown: The computer should be shutdown when reached */ | ||
140 | nv_wr32(therm, 0x20484, sensor->thrs_shutdown.hysteresis); | ||
141 | nv_wr32(therm, 0x20480, sensor->thrs_shutdown.temp); | ||
142 | |||
143 | /* THRS_1 : fan boost*/ | ||
144 | nv_wr32(therm, 0x204c4, sensor->thrs_fan_boost.temp); | ||
145 | |||
146 | /* THRS_2 : critical */ | ||
147 | nv_wr32(therm, 0x204c0, sensor->thrs_critical.temp); | ||
148 | |||
149 | /* THRS_4 : down clock */ | ||
150 | nv_wr32(therm, 0x20414, sensor->thrs_down_clock.temp); | ||
151 | spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); | ||
152 | |||
153 | nv_info(therm, | ||
154 | "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", | ||
155 | sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis, | ||
156 | sensor->thrs_down_clock.temp, | ||
157 | sensor->thrs_down_clock.hysteresis, | ||
158 | sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis, | ||
159 | sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis); | ||
160 | |||
161 | } | ||
162 | |||
163 | /* must be called with alarm_program_lock taken ! */ | ||
164 | static void | ||
165 | nv50_therm_threshold_hyst_emulation(struct nouveau_therm *therm, | ||
166 | uint32_t thrs_reg, u8 status_bit, | ||
167 | const struct nvbios_therm_threshold *thrs, | ||
168 | enum nouveau_therm_thrs thrs_name) | ||
169 | { | ||
170 | enum nouveau_therm_thrs_direction direction; | ||
171 | enum nouveau_therm_thrs_state prev_state, new_state; | ||
172 | int temp, cur; | ||
173 | |||
174 | prev_state = nouveau_therm_sensor_get_threshold_state(therm, thrs_name); | ||
175 | temp = nv_rd32(therm, thrs_reg); | ||
176 | |||
177 | /* program the next threshold */ | ||
178 | if (temp == thrs->temp) { | ||
179 | nv_wr32(therm, thrs_reg, thrs->temp - thrs->hysteresis); | ||
180 | new_state = NOUVEAU_THERM_THRS_HIGHER; | ||
181 | } else { | ||
182 | nv_wr32(therm, thrs_reg, thrs->temp); | ||
183 | new_state = NOUVEAU_THERM_THRS_LOWER; | ||
184 | } | ||
185 | |||
186 | /* fix the state (in case someone reprogrammed the alarms) */ | ||
187 | cur = therm->temp_get(therm); | ||
188 | if (new_state == NOUVEAU_THERM_THRS_LOWER && cur > thrs->temp) | ||
189 | new_state = NOUVEAU_THERM_THRS_HIGHER; | ||
190 | else if (new_state == NOUVEAU_THERM_THRS_HIGHER && | ||
191 | cur < thrs->temp - thrs->hysteresis) | ||
192 | new_state = NOUVEAU_THERM_THRS_LOWER; | ||
193 | nouveau_therm_sensor_set_threshold_state(therm, thrs_name, new_state); | ||
194 | |||
195 | /* find the direction */ | ||
196 | if (prev_state < new_state) | ||
197 | direction = NOUVEAU_THERM_THRS_RISING; | ||
198 | else if (prev_state > new_state) | ||
199 | direction = NOUVEAU_THERM_THRS_FALLING; | ||
200 | else | ||
201 | return; | ||
202 | |||
203 | /* advertise a change in direction */ | ||
204 | nouveau_therm_sensor_event(therm, thrs_name, direction); | ||
205 | } | ||
206 | |||
207 | static void | ||
208 | nv50_therm_intr(struct nouveau_subdev *subdev) | ||
209 | { | ||
210 | struct nouveau_therm *therm = nouveau_therm(subdev); | ||
211 | struct nouveau_therm_priv *priv = (void *)therm; | ||
212 | struct nvbios_therm_sensor *sensor = &priv->bios_sensor; | ||
213 | unsigned long flags; | ||
214 | uint32_t intr; | ||
215 | |||
216 | spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); | ||
217 | |||
218 | intr = nv_rd32(therm, 0x20100); | ||
219 | |||
220 | /* THRS_4: downclock */ | ||
221 | if (intr & 0x002) { | ||
222 | nv50_therm_threshold_hyst_emulation(therm, 0x20414, 24, | ||
223 | &sensor->thrs_down_clock, | ||
224 | NOUVEAU_THERM_THRS_DOWNCLOCK); | ||
225 | intr &= ~0x002; | ||
226 | } | ||
227 | |||
228 | /* shutdown */ | ||
229 | if (intr & 0x004) { | ||
230 | nv50_therm_threshold_hyst_emulation(therm, 0x20480, 20, | ||
231 | &sensor->thrs_shutdown, | ||
232 | NOUVEAU_THERM_THRS_SHUTDOWN); | ||
233 | intr &= ~0x004; | ||
234 | } | ||
235 | |||
236 | /* THRS_1 : fan boost */ | ||
237 | if (intr & 0x008) { | ||
238 | nv50_therm_threshold_hyst_emulation(therm, 0x204c4, 21, | ||
239 | &sensor->thrs_fan_boost, | ||
240 | NOUVEAU_THERM_THRS_FANBOOST); | ||
241 | intr &= ~0x008; | ||
242 | } | ||
243 | |||
244 | /* THRS_2 : critical */ | ||
245 | if (intr & 0x010) { | ||
246 | nv50_therm_threshold_hyst_emulation(therm, 0x204c0, 22, | ||
247 | &sensor->thrs_critical, | ||
248 | NOUVEAU_THERM_THRS_CRITICAL); | ||
249 | intr &= ~0x010; | ||
250 | } | ||
251 | |||
252 | if (intr) | ||
253 | nv_error(therm, "unhandled intr 0x%08x\n", intr); | ||
254 | |||
255 | /* ACK everything */ | ||
256 | nv_wr32(therm, 0x20100, 0xffffffff); | ||
257 | nv_wr32(therm, 0x1100, 0x10000); /* PBUS */ | ||
258 | |||
259 | spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); | ||
260 | } | ||
261 | |||
114 | static int | 262 | static int |
115 | nv50_therm_ctor(struct nouveau_object *parent, | 263 | nv50_therm_ctor(struct nouveau_object *parent, |
116 | struct nouveau_object *engine, | 264 | struct nouveau_object *engine, |
117 | struct nouveau_oclass *oclass, void *data, u32 size, | 265 | struct nouveau_oclass *oclass, void *data, u32 size, |
118 | struct nouveau_object **pobject) | 266 | struct nouveau_object **pobject) |
119 | { | 267 | { |
120 | struct nouveau_therm_priv *priv; | 268 | struct nv50_therm_priv *priv; |
121 | struct nouveau_therm *therm; | ||
122 | int ret; | 269 | int ret; |
123 | 270 | ||
124 | ret = nouveau_therm_create(parent, engine, oclass, &priv); | 271 | ret = nouveau_therm_create(parent, engine, oclass, &priv); |
125 | *pobject = nv_object(priv); | 272 | *pobject = nv_object(priv); |
126 | therm = (void *) priv; | ||
127 | if (ret) | 273 | if (ret) |
128 | return ret; | 274 | return ret; |
129 | 275 | ||
130 | nouveau_therm_ic_ctor(therm); | 276 | priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl; |
131 | nouveau_therm_sensor_ctor(therm); | 277 | priv->base.base.pwm_get = nv50_fan_pwm_get; |
132 | nouveau_therm_fan_ctor(therm); | 278 | priv->base.base.pwm_set = nv50_fan_pwm_set; |
279 | priv->base.base.pwm_clock = nv50_fan_pwm_clock; | ||
280 | priv->base.base.temp_get = nv50_temp_get; | ||
281 | priv->base.sensor.program_alarms = nv50_therm_program_alarms; | ||
282 | nv_subdev(priv)->intr = nv50_therm_intr; | ||
133 | 283 | ||
134 | priv->fan.pwm_get = nv50_fan_pwm_get; | 284 | /* init the thresholds */ |
135 | priv->fan.pwm_set = nv50_fan_pwm_set; | 285 | nouveau_therm_sensor_set_threshold_state(&priv->base.base, |
136 | priv->fan.pwm_clock = nv50_fan_pwm_clock; | 286 | NOUVEAU_THERM_THRS_SHUTDOWN, |
287 | NOUVEAU_THERM_THRS_LOWER); | ||
288 | nouveau_therm_sensor_set_threshold_state(&priv->base.base, | ||
289 | NOUVEAU_THERM_THRS_FANBOOST, | ||
290 | NOUVEAU_THERM_THRS_LOWER); | ||
291 | nouveau_therm_sensor_set_threshold_state(&priv->base.base, | ||
292 | NOUVEAU_THERM_THRS_CRITICAL, | ||
293 | NOUVEAU_THERM_THRS_LOWER); | ||
294 | nouveau_therm_sensor_set_threshold_state(&priv->base.base, | ||
295 | NOUVEAU_THERM_THRS_DOWNCLOCK, | ||
296 | NOUVEAU_THERM_THRS_LOWER); | ||
137 | 297 | ||
138 | therm->temp_get = nv50_temp_get; | 298 | return nouveau_therm_preinit(&priv->base.base); |
139 | therm->fan_get = nouveau_therm_fan_user_get; | ||
140 | therm->fan_set = nouveau_therm_fan_user_set; | ||
141 | therm->fan_sense = nouveau_therm_fan_sense; | ||
142 | therm->attr_get = nouveau_therm_attr_get; | ||
143 | therm->attr_set = nouveau_therm_attr_set; | ||
144 | |||
145 | return 0; | ||
146 | } | 299 | } |
147 | 300 | ||
148 | struct nouveau_oclass | 301 | struct nouveau_oclass |
@@ -151,7 +304,7 @@ nv50_therm_oclass = { | |||
151 | .ofuncs = &(struct nouveau_ofuncs) { | 304 | .ofuncs = &(struct nouveau_ofuncs) { |
152 | .ctor = nv50_therm_ctor, | 305 | .ctor = nv50_therm_ctor, |
153 | .dtor = _nouveau_therm_dtor, | 306 | .dtor = _nouveau_therm_dtor, |
154 | .init = nouveau_therm_init, | 307 | .init = _nouveau_therm_init, |
155 | .fini = nouveau_therm_fini, | 308 | .fini = _nouveau_therm_fini, |
156 | }, | 309 | }, |
157 | }; | 310 | }; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c new file mode 100644 index 000000000000..2dcc5437116a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Ben Skeggs | ||
23 | */ | ||
24 | |||
25 | #include <subdev/gpio.h> | ||
26 | |||
27 | #include "priv.h" | ||
28 | |||
29 | struct nva3_therm_priv { | ||
30 | struct nouveau_therm_priv base; | ||
31 | }; | ||
32 | |||
33 | int | ||
34 | nva3_therm_fan_sense(struct nouveau_therm *therm) | ||
35 | { | ||
36 | u32 tach = nv_rd32(therm, 0x00e728) & 0x0000ffff; | ||
37 | u32 ctrl = nv_rd32(therm, 0x00e720); | ||
38 | if (ctrl & 0x00000001) | ||
39 | return tach * 60; | ||
40 | return -ENODEV; | ||
41 | } | ||
42 | |||
43 | static int | ||
44 | nva3_therm_init(struct nouveau_object *object) | ||
45 | { | ||
46 | struct nva3_therm_priv *priv = (void *)object; | ||
47 | struct dcb_gpio_func *tach = &priv->base.fan->tach; | ||
48 | int ret; | ||
49 | |||
50 | ret = nouveau_therm_init(&priv->base.base); | ||
51 | if (ret) | ||
52 | return ret; | ||
53 | |||
54 | /* enable fan tach, count revolutions per-second */ | ||
55 | nv_mask(priv, 0x00e720, 0x00000003, 0x00000002); | ||
56 | if (tach->func != DCB_GPIO_UNUSED) { | ||
57 | nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000); | ||
58 | nv_mask(priv, 0x00e720, 0x001f0000, tach->line << 16); | ||
59 | nv_mask(priv, 0x00e720, 0x00000001, 0x00000001); | ||
60 | } | ||
61 | nv_mask(priv, 0x00e720, 0x00000002, 0x00000000); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int | ||
67 | nva3_therm_ctor(struct nouveau_object *parent, | ||
68 | struct nouveau_object *engine, | ||
69 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
70 | struct nouveau_object **pobject) | ||
71 | { | ||
72 | struct nva3_therm_priv *priv; | ||
73 | int ret; | ||
74 | |||
75 | ret = nouveau_therm_create(parent, engine, oclass, &priv); | ||
76 | *pobject = nv_object(priv); | ||
77 | if (ret) | ||
78 | return ret; | ||
79 | |||
80 | priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl; | ||
81 | priv->base.base.pwm_get = nv50_fan_pwm_get; | ||
82 | priv->base.base.pwm_set = nv50_fan_pwm_set; | ||
83 | priv->base.base.pwm_clock = nv50_fan_pwm_clock; | ||
84 | priv->base.base.temp_get = nv50_temp_get; | ||
85 | priv->base.base.fan_sense = nva3_therm_fan_sense; | ||
86 | priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling; | ||
87 | return nouveau_therm_preinit(&priv->base.base); | ||
88 | } | ||
89 | |||
90 | struct nouveau_oclass | ||
91 | nva3_therm_oclass = { | ||
92 | .handle = NV_SUBDEV(THERM, 0xa3), | ||
93 | .ofuncs = &(struct nouveau_ofuncs) { | ||
94 | .ctor = nva3_therm_ctor, | ||
95 | .dtor = _nouveau_therm_dtor, | ||
96 | .init = nva3_therm_init, | ||
97 | .fini = _nouveau_therm_fini, | ||
98 | }, | ||
99 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c new file mode 100644 index 000000000000..d7d30ee8332e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c | |||
@@ -0,0 +1,153 @@ | |||
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 | struct nvd0_therm_priv { | ||
28 | struct nouveau_therm_priv base; | ||
29 | }; | ||
30 | |||
31 | static int | ||
32 | pwm_info(struct nouveau_therm *therm, int line) | ||
33 | { | ||
34 | u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04)); | ||
35 | switch (gpio & 0x000000c0) { | ||
36 | case 0x00000000: /* normal mode, possibly pwm forced off by us */ | ||
37 | case 0x00000040: /* nvio special */ | ||
38 | switch (gpio & 0x0000001f) { | ||
39 | case 0x19: return 1; | ||
40 | case 0x1c: return 0; | ||
41 | default: | ||
42 | break; | ||
43 | } | ||
44 | default: | ||
45 | break; | ||
46 | } | ||
47 | |||
48 | nv_error(therm, "GPIO %d unknown PWM: 0x%08x\n", line, gpio); | ||
49 | return -ENODEV; | ||
50 | } | ||
51 | |||
52 | static int | ||
53 | nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) | ||
54 | { | ||
55 | u32 data = enable ? 0x00000040 : 0x00000000; | ||
56 | int indx = pwm_info(therm, line); | ||
57 | if (indx < 0) | ||
58 | return indx; | ||
59 | |||
60 | nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static int | ||
65 | nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) | ||
66 | { | ||
67 | int indx = pwm_info(therm, line); | ||
68 | if (indx < 0) | ||
69 | return indx; | ||
70 | |||
71 | if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { | ||
72 | *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); | ||
73 | *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | return -EINVAL; | ||
78 | } | ||
79 | |||
80 | static int | ||
81 | nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) | ||
82 | { | ||
83 | int indx = pwm_info(therm, line); | ||
84 | if (indx < 0) | ||
85 | return indx; | ||
86 | |||
87 | nv_wr32(therm, 0x00e114 + (indx * 8), divs); | ||
88 | nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000); | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int | ||
93 | nvd0_fan_pwm_clock(struct nouveau_therm *therm) | ||
94 | { | ||
95 | return (nv_device(therm)->crystal * 1000) / 20; | ||
96 | } | ||
97 | |||
98 | static int | ||
99 | nvd0_therm_init(struct nouveau_object *object) | ||
100 | { | ||
101 | struct nvd0_therm_priv *priv = (void *)object; | ||
102 | int ret; | ||
103 | |||
104 | ret = nouveau_therm_init(&priv->base.base); | ||
105 | if (ret) | ||
106 | return ret; | ||
107 | |||
108 | /* enable fan tach, count revolutions per-second */ | ||
109 | nv_mask(priv, 0x00e720, 0x00000003, 0x00000002); | ||
110 | if (priv->base.fan->tach.func != DCB_GPIO_UNUSED) { | ||
111 | nv_mask(priv, 0x00d79c, 0x000000ff, priv->base.fan->tach.line); | ||
112 | nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000); | ||
113 | nv_mask(priv, 0x00e720, 0x00000001, 0x00000001); | ||
114 | } | ||
115 | nv_mask(priv, 0x00e720, 0x00000002, 0x00000000); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int | ||
121 | nvd0_therm_ctor(struct nouveau_object *parent, | ||
122 | struct nouveau_object *engine, | ||
123 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
124 | struct nouveau_object **pobject) | ||
125 | { | ||
126 | struct nvd0_therm_priv *priv; | ||
127 | int ret; | ||
128 | |||
129 | ret = nouveau_therm_create(parent, engine, oclass, &priv); | ||
130 | *pobject = nv_object(priv); | ||
131 | if (ret) | ||
132 | return ret; | ||
133 | |||
134 | priv->base.base.pwm_ctrl = nvd0_fan_pwm_ctrl; | ||
135 | priv->base.base.pwm_get = nvd0_fan_pwm_get; | ||
136 | priv->base.base.pwm_set = nvd0_fan_pwm_set; | ||
137 | priv->base.base.pwm_clock = nvd0_fan_pwm_clock; | ||
138 | priv->base.base.temp_get = nv50_temp_get; | ||
139 | priv->base.base.fan_sense = nva3_therm_fan_sense; | ||
140 | priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling; | ||
141 | return nouveau_therm_preinit(&priv->base.base); | ||
142 | } | ||
143 | |||
144 | struct nouveau_oclass | ||
145 | nvd0_therm_oclass = { | ||
146 | .handle = NV_SUBDEV(THERM, 0xd0), | ||
147 | .ofuncs = &(struct nouveau_ofuncs) { | ||
148 | .ctor = nvd0_therm_ctor, | ||
149 | .dtor = _nouveau_therm_dtor, | ||
150 | .init = nvd0_therm_init, | ||
151 | .fini = _nouveau_therm_fini, | ||
152 | }, | ||
153 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h index 1c3cd6abc36e..06b98706b3fc 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h | |||
@@ -1,3 +1,6 @@ | |||
1 | #ifndef __NVTHERM_PRIV_H__ | ||
2 | #define __NVTHERM_PRIV_H__ | ||
3 | |||
1 | /* | 4 | /* |
2 | * Copyright 2012 The Nouveau community | 5 | * Copyright 2012 The Nouveau community |
3 | * | 6 | * |
@@ -25,33 +28,81 @@ | |||
25 | #include <subdev/therm.h> | 28 | #include <subdev/therm.h> |
26 | 29 | ||
27 | #include <subdev/bios/extdev.h> | 30 | #include <subdev/bios/extdev.h> |
31 | #include <subdev/bios/gpio.h> | ||
28 | #include <subdev/bios/perf.h> | 32 | #include <subdev/bios/perf.h> |
29 | #include <subdev/bios/therm.h> | 33 | #include <subdev/bios/therm.h> |
34 | #include <subdev/timer.h> | ||
35 | |||
36 | struct nouveau_fan { | ||
37 | struct nouveau_therm *parent; | ||
38 | const char *type; | ||
39 | |||
40 | struct nvbios_therm_fan bios; | ||
41 | struct nvbios_perf_fan perf; | ||
42 | |||
43 | struct nouveau_alarm alarm; | ||
44 | spinlock_t lock; | ||
45 | int percent; | ||
46 | |||
47 | int (*get)(struct nouveau_therm *therm); | ||
48 | int (*set)(struct nouveau_therm *therm, int percent); | ||
49 | |||
50 | struct dcb_gpio_func tach; | ||
51 | }; | ||
52 | |||
53 | enum nouveau_therm_thrs_direction { | ||
54 | NOUVEAU_THERM_THRS_FALLING = 0, | ||
55 | NOUVEAU_THERM_THRS_RISING = 1 | ||
56 | }; | ||
57 | |||
58 | enum nouveau_therm_thrs_state { | ||
59 | NOUVEAU_THERM_THRS_LOWER = 0, | ||
60 | NOUVEAU_THERM_THRS_HIGHER = 1 | ||
61 | }; | ||
62 | |||
63 | enum nouveau_therm_thrs { | ||
64 | NOUVEAU_THERM_THRS_FANBOOST = 0, | ||
65 | NOUVEAU_THERM_THRS_DOWNCLOCK = 1, | ||
66 | NOUVEAU_THERM_THRS_CRITICAL = 2, | ||
67 | NOUVEAU_THERM_THRS_SHUTDOWN = 3, | ||
68 | NOUVEAU_THERM_THRS_NR | ||
69 | }; | ||
30 | 70 | ||
31 | struct nouveau_therm_priv { | 71 | struct nouveau_therm_priv { |
32 | struct nouveau_therm base; | 72 | struct nouveau_therm base; |
33 | 73 | ||
74 | /* automatic thermal management */ | ||
75 | struct nouveau_alarm alarm; | ||
76 | spinlock_t lock; | ||
77 | struct nouveau_therm_trip_point *last_trip; | ||
78 | int mode; | ||
79 | int suspend; | ||
80 | |||
34 | /* bios */ | 81 | /* bios */ |
35 | struct nvbios_therm_sensor bios_sensor; | 82 | struct nvbios_therm_sensor bios_sensor; |
36 | struct nvbios_therm_fan bios_fan; | ||
37 | struct nvbios_perf_fan bios_perf_fan; | ||
38 | 83 | ||
39 | /* fan priv */ | 84 | /* fan priv */ |
85 | struct nouveau_fan *fan; | ||
86 | |||
87 | /* alarms priv */ | ||
40 | struct { | 88 | struct { |
41 | enum nouveau_therm_fan_mode mode; | 89 | spinlock_t alarm_program_lock; |
42 | int percent; | 90 | struct nouveau_alarm therm_poll_alarm; |
91 | enum nouveau_therm_thrs_state alarm_state[NOUVEAU_THERM_THRS_NR]; | ||
92 | void (*program_alarms)(struct nouveau_therm *); | ||
93 | } sensor; | ||
43 | 94 | ||
44 | int (*pwm_get)(struct nouveau_therm *, int line, u32*, u32*); | 95 | /* what should be done if the card overheats */ |
45 | int (*pwm_set)(struct nouveau_therm *, int line, u32, u32); | 96 | struct { |
46 | int (*pwm_clock)(struct nouveau_therm *); | 97 | void (*downclock)(struct nouveau_therm *, bool active); |
47 | } fan; | 98 | void (*pause)(struct nouveau_therm *, bool active); |
99 | } emergency; | ||
48 | 100 | ||
49 | /* ic */ | 101 | /* ic */ |
50 | struct i2c_client *ic; | 102 | struct i2c_client *ic; |
51 | }; | 103 | }; |
52 | 104 | ||
53 | int nouveau_therm_init(struct nouveau_object *object); | 105 | int nouveau_therm_mode(struct nouveau_therm *therm, int mode); |
54 | int nouveau_therm_fini(struct nouveau_object *object, bool suspend); | ||
55 | int nouveau_therm_attr_get(struct nouveau_therm *therm, | 106 | int nouveau_therm_attr_get(struct nouveau_therm *therm, |
56 | enum nouveau_therm_attr_type type); | 107 | enum nouveau_therm_attr_type type); |
57 | int nouveau_therm_attr_set(struct nouveau_therm *therm, | 108 | int nouveau_therm_attr_set(struct nouveau_therm *therm, |
@@ -63,11 +114,35 @@ int nouveau_therm_sensor_ctor(struct nouveau_therm *therm); | |||
63 | 114 | ||
64 | int nouveau_therm_fan_ctor(struct nouveau_therm *therm); | 115 | int nouveau_therm_fan_ctor(struct nouveau_therm *therm); |
65 | int nouveau_therm_fan_get(struct nouveau_therm *therm); | 116 | int nouveau_therm_fan_get(struct nouveau_therm *therm); |
66 | int nouveau_therm_fan_set(struct nouveau_therm *therm, int percent); | 117 | int nouveau_therm_fan_set(struct nouveau_therm *therm, bool now, int percent); |
67 | int nouveau_therm_fan_user_get(struct nouveau_therm *therm); | 118 | int nouveau_therm_fan_user_get(struct nouveau_therm *therm); |
68 | int nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent); | 119 | int nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent); |
69 | int nouveau_therm_fan_set_mode(struct nouveau_therm *therm, | ||
70 | enum nouveau_therm_fan_mode mode); | ||
71 | |||
72 | 120 | ||
73 | int nouveau_therm_fan_sense(struct nouveau_therm *therm); | 121 | int nouveau_therm_fan_sense(struct nouveau_therm *therm); |
122 | |||
123 | int nouveau_therm_preinit(struct nouveau_therm *); | ||
124 | |||
125 | void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm, | ||
126 | enum nouveau_therm_thrs thrs, | ||
127 | enum nouveau_therm_thrs_state st); | ||
128 | enum nouveau_therm_thrs_state | ||
129 | nouveau_therm_sensor_get_threshold_state(struct nouveau_therm *therm, | ||
130 | enum nouveau_therm_thrs thrs); | ||
131 | void nouveau_therm_sensor_event(struct nouveau_therm *therm, | ||
132 | enum nouveau_therm_thrs thrs, | ||
133 | enum nouveau_therm_thrs_direction dir); | ||
134 | void nouveau_therm_program_alarms_polling(struct nouveau_therm *therm); | ||
135 | |||
136 | int nv50_fan_pwm_ctrl(struct nouveau_therm *, int, bool); | ||
137 | int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *); | ||
138 | int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32); | ||
139 | int nv50_fan_pwm_clock(struct nouveau_therm *); | ||
140 | int nv50_temp_get(struct nouveau_therm *therm); | ||
141 | |||
142 | int nva3_therm_fan_sense(struct nouveau_therm *); | ||
143 | |||
144 | int nouveau_fanpwm_create(struct nouveau_therm *, struct dcb_gpio_func *); | ||
145 | int nouveau_fantog_create(struct nouveau_therm *, struct dcb_gpio_func *); | ||
146 | int nouveau_fannil_create(struct nouveau_therm *); | ||
147 | |||
148 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c index 204282301fb1..b37624af8297 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c | |||
@@ -58,11 +58,171 @@ static void | |||
58 | nouveau_therm_temp_safety_checks(struct nouveau_therm *therm) | 58 | nouveau_therm_temp_safety_checks(struct nouveau_therm *therm) |
59 | { | 59 | { |
60 | struct nouveau_therm_priv *priv = (void *)therm; | 60 | struct nouveau_therm_priv *priv = (void *)therm; |
61 | struct nvbios_therm_sensor *s = &priv->bios_sensor; | ||
61 | 62 | ||
62 | if (!priv->bios_sensor.slope_div) | 63 | if (!priv->bios_sensor.slope_div) |
63 | priv->bios_sensor.slope_div = 1; | 64 | priv->bios_sensor.slope_div = 1; |
64 | if (!priv->bios_sensor.offset_den) | 65 | if (!priv->bios_sensor.offset_den) |
65 | priv->bios_sensor.offset_den = 1; | 66 | priv->bios_sensor.offset_den = 1; |
67 | |||
68 | /* enforce a minimum hysteresis on thresholds */ | ||
69 | s->thrs_fan_boost.hysteresis = max_t(u8, s->thrs_fan_boost.hysteresis, 2); | ||
70 | s->thrs_down_clock.hysteresis = max_t(u8, s->thrs_down_clock.hysteresis, 2); | ||
71 | s->thrs_critical.hysteresis = max_t(u8, s->thrs_critical.hysteresis, 2); | ||
72 | s->thrs_shutdown.hysteresis = max_t(u8, s->thrs_shutdown.hysteresis, 2); | ||
73 | } | ||
74 | |||
75 | /* must be called with alarm_program_lock taken ! */ | ||
76 | void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm, | ||
77 | enum nouveau_therm_thrs thrs, | ||
78 | enum nouveau_therm_thrs_state st) | ||
79 | { | ||
80 | struct nouveau_therm_priv *priv = (void *)therm; | ||
81 | priv->sensor.alarm_state[thrs] = st; | ||
82 | } | ||
83 | |||
84 | /* must be called with alarm_program_lock taken ! */ | ||
85 | enum nouveau_therm_thrs_state | ||
86 | nouveau_therm_sensor_get_threshold_state(struct nouveau_therm *therm, | ||
87 | enum nouveau_therm_thrs thrs) | ||
88 | { | ||
89 | struct nouveau_therm_priv *priv = (void *)therm; | ||
90 | return priv->sensor.alarm_state[thrs]; | ||
91 | } | ||
92 | |||
93 | static void | ||
94 | nv_poweroff_work(struct work_struct *work) | ||
95 | { | ||
96 | orderly_poweroff(true); | ||
97 | kfree(work); | ||
98 | } | ||
99 | |||
100 | void nouveau_therm_sensor_event(struct nouveau_therm *therm, | ||
101 | enum nouveau_therm_thrs thrs, | ||
102 | enum nouveau_therm_thrs_direction dir) | ||
103 | { | ||
104 | struct nouveau_therm_priv *priv = (void *)therm; | ||
105 | bool active; | ||
106 | const char *thresolds[] = { | ||
107 | "fanboost", "downclock", "critical", "shutdown" | ||
108 | }; | ||
109 | uint8_t temperature = therm->temp_get(therm); | ||
110 | |||
111 | if (thrs < 0 || thrs > 3) | ||
112 | return; | ||
113 | |||
114 | if (dir == NOUVEAU_THERM_THRS_FALLING) | ||
115 | nv_info(therm, "temperature (%u C) went below the '%s' threshold\n", | ||
116 | temperature, thresolds[thrs]); | ||
117 | else | ||
118 | nv_info(therm, "temperature (%u C) hit the '%s' threshold\n", | ||
119 | temperature, thresolds[thrs]); | ||
120 | |||
121 | active = (dir == NOUVEAU_THERM_THRS_RISING); | ||
122 | switch (thrs) { | ||
123 | case NOUVEAU_THERM_THRS_FANBOOST: | ||
124 | if (active) { | ||
125 | nouveau_therm_fan_set(therm, true, 100); | ||
126 | nouveau_therm_mode(therm, NOUVEAU_THERM_CTRL_AUTO); | ||
127 | } | ||
128 | break; | ||
129 | case NOUVEAU_THERM_THRS_DOWNCLOCK: | ||
130 | if (priv->emergency.downclock) | ||
131 | priv->emergency.downclock(therm, active); | ||
132 | break; | ||
133 | case NOUVEAU_THERM_THRS_CRITICAL: | ||
134 | if (priv->emergency.pause) | ||
135 | priv->emergency.pause(therm, active); | ||
136 | break; | ||
137 | case NOUVEAU_THERM_THRS_SHUTDOWN: | ||
138 | if (active) { | ||
139 | struct work_struct *work; | ||
140 | |||
141 | work = kmalloc(sizeof(*work), GFP_ATOMIC); | ||
142 | if (work) { | ||
143 | INIT_WORK(work, nv_poweroff_work); | ||
144 | schedule_work(work); | ||
145 | } | ||
146 | } | ||
147 | break; | ||
148 | case NOUVEAU_THERM_THRS_NR: | ||
149 | break; | ||
150 | } | ||
151 | |||
152 | } | ||
153 | |||
154 | /* must be called with alarm_program_lock taken ! */ | ||
155 | static void | ||
156 | nouveau_therm_threshold_hyst_polling(struct nouveau_therm *therm, | ||
157 | const struct nvbios_therm_threshold *thrs, | ||
158 | enum nouveau_therm_thrs thrs_name) | ||
159 | { | ||
160 | enum nouveau_therm_thrs_direction direction; | ||
161 | enum nouveau_therm_thrs_state prev_state, new_state; | ||
162 | int temp = therm->temp_get(therm); | ||
163 | |||
164 | prev_state = nouveau_therm_sensor_get_threshold_state(therm, thrs_name); | ||
165 | |||
166 | if (temp >= thrs->temp && prev_state == NOUVEAU_THERM_THRS_LOWER) { | ||
167 | direction = NOUVEAU_THERM_THRS_RISING; | ||
168 | new_state = NOUVEAU_THERM_THRS_HIGHER; | ||
169 | } else if (temp <= thrs->temp - thrs->hysteresis && | ||
170 | prev_state == NOUVEAU_THERM_THRS_HIGHER) { | ||
171 | direction = NOUVEAU_THERM_THRS_FALLING; | ||
172 | new_state = NOUVEAU_THERM_THRS_LOWER; | ||
173 | } else | ||
174 | return; /* nothing to do */ | ||
175 | |||
176 | nouveau_therm_sensor_set_threshold_state(therm, thrs_name, new_state); | ||
177 | nouveau_therm_sensor_event(therm, thrs_name, direction); | ||
178 | } | ||
179 | |||
180 | static void | ||
181 | alarm_timer_callback(struct nouveau_alarm *alarm) | ||
182 | { | ||
183 | struct nouveau_therm_priv *priv = | ||
184 | container_of(alarm, struct nouveau_therm_priv, sensor.therm_poll_alarm); | ||
185 | struct nvbios_therm_sensor *sensor = &priv->bios_sensor; | ||
186 | struct nouveau_timer *ptimer = nouveau_timer(priv); | ||
187 | struct nouveau_therm *therm = &priv->base; | ||
188 | unsigned long flags; | ||
189 | |||
190 | spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); | ||
191 | |||
192 | nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost, | ||
193 | NOUVEAU_THERM_THRS_FANBOOST); | ||
194 | |||
195 | nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_down_clock, | ||
196 | NOUVEAU_THERM_THRS_DOWNCLOCK); | ||
197 | |||
198 | nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_critical, | ||
199 | NOUVEAU_THERM_THRS_CRITICAL); | ||
200 | |||
201 | nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_shutdown, | ||
202 | NOUVEAU_THERM_THRS_SHUTDOWN); | ||
203 | |||
204 | /* schedule the next poll in one second */ | ||
205 | if (list_empty(&alarm->head)) | ||
206 | ptimer->alarm(ptimer, 1000 * 1000 * 1000, alarm); | ||
207 | |||
208 | spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); | ||
209 | } | ||
210 | |||
211 | void | ||
212 | nouveau_therm_program_alarms_polling(struct nouveau_therm *therm) | ||
213 | { | ||
214 | struct nouveau_therm_priv *priv = (void *)therm; | ||
215 | struct nvbios_therm_sensor *sensor = &priv->bios_sensor; | ||
216 | |||
217 | nv_info(therm, | ||
218 | "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", | ||
219 | sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis, | ||
220 | sensor->thrs_down_clock.temp, | ||
221 | sensor->thrs_down_clock.hysteresis, | ||
222 | sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis, | ||
223 | sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis); | ||
224 | |||
225 | alarm_timer_callback(&priv->sensor.therm_poll_alarm); | ||
66 | } | 226 | } |
67 | 227 | ||
68 | int | 228 | int |
@@ -71,6 +231,8 @@ nouveau_therm_sensor_ctor(struct nouveau_therm *therm) | |||
71 | struct nouveau_therm_priv *priv = (void *)therm; | 231 | struct nouveau_therm_priv *priv = (void *)therm; |
72 | struct nouveau_bios *bios = nouveau_bios(therm); | 232 | struct nouveau_bios *bios = nouveau_bios(therm); |
73 | 233 | ||
234 | nouveau_alarm_init(&priv->sensor.therm_poll_alarm, alarm_timer_callback); | ||
235 | |||
74 | nouveau_therm_temp_set_defaults(therm); | 236 | nouveau_therm_temp_set_defaults(therm); |
75 | if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE, | 237 | if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE, |
76 | &priv->bios_sensor)) | 238 | &priv->bios_sensor)) |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c index c26ca9bef671..8e1bae4f12e8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c | |||
@@ -79,7 +79,7 @@ nv04_timer_alarm_trigger(struct nouveau_timer *ptimer) | |||
79 | 79 | ||
80 | /* execute any pending alarm handlers */ | 80 | /* execute any pending alarm handlers */ |
81 | list_for_each_entry_safe(alarm, atemp, &exec, head) { | 81 | list_for_each_entry_safe(alarm, atemp, &exec, head) { |
82 | list_del(&alarm->head); | 82 | list_del_init(&alarm->head); |
83 | alarm->func(alarm); | 83 | alarm->func(alarm); |
84 | } | 84 | } |
85 | } | 85 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.h b/drivers/gpu/drm/nouveau/nouveau_acpi.h index d0da230d7706..74acf0f87785 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.h +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.h | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | #define ROM_BIOS_PAGE 4096 | 4 | #define ROM_BIOS_PAGE 4096 |
5 | 5 | ||
6 | #if defined(CONFIG_ACPI) | 6 | #if defined(CONFIG_ACPI) && defined(CONFIG_X86) |
7 | bool nouveau_is_optimus(void); | 7 | bool nouveau_is_optimus(void); |
8 | bool nouveau_is_v1_dsm(void); | 8 | bool nouveau_is_v1_dsm(void); |
9 | void nouveau_register_dsm_handler(void); | 9 | void nouveau_register_dsm_handler(void); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index f65b20a375f6..5d940302d2aa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c | |||
@@ -84,6 +84,8 @@ nv40_backlight_init(struct drm_connector *connector) | |||
84 | props.max_brightness = 31; | 84 | props.max_brightness = 31; |
85 | bd = backlight_device_register("nv_backlight", &connector->kdev, drm, | 85 | bd = backlight_device_register("nv_backlight", &connector->kdev, drm, |
86 | &nv40_bl_ops, &props); | 86 | &nv40_bl_ops, &props); |
87 | if (IS_ERR(bd)) | ||
88 | return PTR_ERR(bd); | ||
87 | drm->backlight = bd; | 89 | drm->backlight = bd; |
88 | bd->props.brightness = nv40_get_intensity(bd); | 90 | bd->props.brightness = nv40_get_intensity(bd); |
89 | backlight_update_status(bd); | 91 | backlight_update_status(bd); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 865eddfa30a7..50a6dd02f7c5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c | |||
@@ -678,23 +678,6 @@ int run_tmds_table(struct drm_device *dev, struct dcb_output *dcbent, int head, | |||
678 | return 0; | 678 | return 0; |
679 | } | 679 | } |
680 | 680 | ||
681 | static void parse_bios_version(struct drm_device *dev, struct nvbios *bios, uint16_t offset) | ||
682 | { | ||
683 | /* | ||
684 | * offset + 0 (8 bits): Micro version | ||
685 | * offset + 1 (8 bits): Minor version | ||
686 | * offset + 2 (8 bits): Chip version | ||
687 | * offset + 3 (8 bits): Major version | ||
688 | */ | ||
689 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
690 | |||
691 | bios->major_version = bios->data[offset + 3]; | ||
692 | bios->chip_version = bios->data[offset + 2]; | ||
693 | NV_INFO(drm, "Bios version %02x.%02x.%02x.%02x\n", | ||
694 | bios->data[offset + 3], bios->data[offset + 2], | ||
695 | bios->data[offset + 1], bios->data[offset]); | ||
696 | } | ||
697 | |||
698 | static void parse_script_table_pointers(struct nvbios *bios, uint16_t offset) | 681 | static void parse_script_table_pointers(struct nvbios *bios, uint16_t offset) |
699 | { | 682 | { |
700 | /* | 683 | /* |
@@ -710,12 +693,6 @@ static void parse_script_table_pointers(struct nvbios *bios, uint16_t offset) | |||
710 | */ | 693 | */ |
711 | 694 | ||
712 | bios->init_script_tbls_ptr = ROM16(bios->data[offset]); | 695 | bios->init_script_tbls_ptr = ROM16(bios->data[offset]); |
713 | bios->macro_index_tbl_ptr = ROM16(bios->data[offset + 2]); | ||
714 | bios->macro_tbl_ptr = ROM16(bios->data[offset + 4]); | ||
715 | bios->condition_tbl_ptr = ROM16(bios->data[offset + 6]); | ||
716 | bios->io_condition_tbl_ptr = ROM16(bios->data[offset + 8]); | ||
717 | bios->io_flag_condition_tbl_ptr = ROM16(bios->data[offset + 10]); | ||
718 | bios->init_function_tbl_ptr = ROM16(bios->data[offset + 12]); | ||
719 | } | 696 | } |
720 | 697 | ||
721 | static int parse_bit_A_tbl_entry(struct drm_device *dev, struct nvbios *bios, struct bit_entry *bitentry) | 698 | static int parse_bit_A_tbl_entry(struct drm_device *dev, struct nvbios *bios, struct bit_entry *bitentry) |
@@ -765,25 +742,6 @@ static int parse_bit_A_tbl_entry(struct drm_device *dev, struct nvbios *bios, st | |||
765 | return 0; | 742 | return 0; |
766 | } | 743 | } |
767 | 744 | ||
768 | static int parse_bit_C_tbl_entry(struct drm_device *dev, struct nvbios *bios, struct bit_entry *bitentry) | ||
769 | { | ||
770 | /* | ||
771 | * offset + 8 (16 bits): PLL limits table pointer | ||
772 | * | ||
773 | * There's more in here, but that's unknown. | ||
774 | */ | ||
775 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
776 | |||
777 | if (bitentry->length < 10) { | ||
778 | NV_ERROR(drm, "Do not understand BIT C table\n"); | ||
779 | return -EINVAL; | ||
780 | } | ||
781 | |||
782 | bios->pll_limit_tbl_ptr = ROM16(bios->data[bitentry->offset + 8]); | ||
783 | |||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | static int parse_bit_display_tbl_entry(struct drm_device *dev, struct nvbios *bios, struct bit_entry *bitentry) | 745 | static int parse_bit_display_tbl_entry(struct drm_device *dev, struct nvbios *bios, struct bit_entry *bitentry) |
788 | { | 746 | { |
789 | /* | 747 | /* |
@@ -821,12 +779,6 @@ static int parse_bit_init_tbl_entry(struct drm_device *dev, struct nvbios *bios, | |||
821 | } | 779 | } |
822 | 780 | ||
823 | parse_script_table_pointers(bios, bitentry->offset); | 781 | parse_script_table_pointers(bios, bitentry->offset); |
824 | |||
825 | if (bitentry->length >= 16) | ||
826 | bios->some_script_ptr = ROM16(bios->data[bitentry->offset + 14]); | ||
827 | if (bitentry->length >= 18) | ||
828 | bios->init96_tbl_ptr = ROM16(bios->data[bitentry->offset + 16]); | ||
829 | |||
830 | return 0; | 782 | return 0; |
831 | } | 783 | } |
832 | 784 | ||
@@ -852,8 +804,6 @@ static int parse_bit_i_tbl_entry(struct drm_device *dev, struct nvbios *bios, st | |||
852 | return -EINVAL; | 804 | return -EINVAL; |
853 | } | 805 | } |
854 | 806 | ||
855 | parse_bios_version(dev, bios, bitentry->offset); | ||
856 | |||
857 | /* | 807 | /* |
858 | * bit 4 seems to indicate a mobile bios (doesn't suffer from BMP's | 808 | * bit 4 seems to indicate a mobile bios (doesn't suffer from BMP's |
859 | * Quadro identity crisis), other bits possibly as for BMP feature byte | 809 | * Quadro identity crisis), other bits possibly as for BMP feature byte |
@@ -1078,9 +1028,6 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset) | |||
1078 | return ret; | 1028 | return ret; |
1079 | if (bios->major_version >= 0x60) /* g80+ */ | 1029 | if (bios->major_version >= 0x60) /* g80+ */ |
1080 | parse_bit_table(bios, bitoffset, &BIT_TABLE('A', A)); | 1030 | parse_bit_table(bios, bitoffset, &BIT_TABLE('A', A)); |
1081 | ret = parse_bit_table(bios, bitoffset, &BIT_TABLE('C', C)); | ||
1082 | if (ret) | ||
1083 | return ret; | ||
1084 | parse_bit_table(bios, bitoffset, &BIT_TABLE('D', display)); | 1031 | parse_bit_table(bios, bitoffset, &BIT_TABLE('D', display)); |
1085 | ret = parse_bit_table(bios, bitoffset, &BIT_TABLE('I', init)); | 1032 | ret = parse_bit_table(bios, bitoffset, &BIT_TABLE('I', init)); |
1086 | if (ret) | 1033 | if (ret) |
@@ -1228,8 +1175,6 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi | |||
1228 | */ | 1175 | */ |
1229 | bios->feature_byte = bmp[9]; | 1176 | bios->feature_byte = bmp[9]; |
1230 | 1177 | ||
1231 | parse_bios_version(dev, bios, offset + 10); | ||
1232 | |||
1233 | if (bmp_version_major < 5 || bmp_version_minor < 0x10) | 1178 | if (bmp_version_major < 5 || bmp_version_minor < 0x10) |
1234 | bios->old_style_init = true; | 1179 | bios->old_style_init = true; |
1235 | legacy_scripts_offset = 18; | 1180 | legacy_scripts_offset = 18; |
@@ -1276,8 +1221,10 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi | |||
1276 | bios->fp.lvdsmanufacturerpointer = ROM16(bmp[117]); | 1221 | bios->fp.lvdsmanufacturerpointer = ROM16(bmp[117]); |
1277 | bios->fp.fpxlatemanufacturertableptr = ROM16(bmp[119]); | 1222 | bios->fp.fpxlatemanufacturertableptr = ROM16(bmp[119]); |
1278 | } | 1223 | } |
1224 | #if 0 | ||
1279 | if (bmplength > 143) | 1225 | if (bmplength > 143) |
1280 | bios->pll_limit_tbl_ptr = ROM16(bmp[142]); | 1226 | bios->pll_limit_tbl_ptr = ROM16(bmp[142]); |
1227 | #endif | ||
1281 | 1228 | ||
1282 | if (bmplength > 157) | 1229 | if (bmplength > 157) |
1283 | bios->fp.duallink_transition_clk = ROM16(bmp[156]) * 10; | 1230 | bios->fp.duallink_transition_clk = ROM16(bmp[156]) * 10; |
@@ -1522,6 +1469,7 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, | |||
1522 | } | 1469 | } |
1523 | case DCB_OUTPUT_DP: | 1470 | case DCB_OUTPUT_DP: |
1524 | entry->dpconf.sor.link = (conf & 0x00000030) >> 4; | 1471 | entry->dpconf.sor.link = (conf & 0x00000030) >> 4; |
1472 | entry->extdev = (conf & 0x0000ff00) >> 8; | ||
1525 | switch ((conf & 0x00e00000) >> 21) { | 1473 | switch ((conf & 0x00e00000) >> 21) { |
1526 | case 0: | 1474 | case 0: |
1527 | entry->dpconf.link_bw = 162000; | 1475 | entry->dpconf.link_bw = 162000; |
@@ -1543,8 +1491,10 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, | |||
1543 | } | 1491 | } |
1544 | break; | 1492 | break; |
1545 | case DCB_OUTPUT_TMDS: | 1493 | case DCB_OUTPUT_TMDS: |
1546 | if (dcb->version >= 0x40) | 1494 | if (dcb->version >= 0x40) { |
1547 | entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; | 1495 | entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; |
1496 | entry->extdev = (conf & 0x0000ff00) >> 8; | ||
1497 | } | ||
1548 | else if (dcb->version >= 0x30) | 1498 | else if (dcb->version >= 0x30) |
1549 | entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8; | 1499 | entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8; |
1550 | else if (dcb->version >= 0x22) | 1500 | else if (dcb->version >= 0x22) |
@@ -1937,9 +1887,9 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios) | |||
1937 | if (conn[0] != 0xff) { | 1887 | if (conn[0] != 0xff) { |
1938 | NV_INFO(drm, "DCB conn %02d: ", idx); | 1888 | NV_INFO(drm, "DCB conn %02d: ", idx); |
1939 | if (olddcb_conntab(dev)[3] < 4) | 1889 | if (olddcb_conntab(dev)[3] < 4) |
1940 | printk("%04x\n", ROM16(conn[0])); | 1890 | pr_cont("%04x\n", ROM16(conn[0])); |
1941 | else | 1891 | else |
1942 | printk("%08x\n", ROM32(conn[0])); | 1892 | pr_cont("%08x\n", ROM32(conn[0])); |
1943 | } | 1893 | } |
1944 | } | 1894 | } |
1945 | dcb_fake_connectors(bios); | 1895 | dcb_fake_connectors(bios); |
@@ -2052,45 +2002,29 @@ uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev) | |||
2052 | static bool NVInitVBIOS(struct drm_device *dev) | 2002 | static bool NVInitVBIOS(struct drm_device *dev) |
2053 | { | 2003 | { |
2054 | struct nouveau_drm *drm = nouveau_drm(dev); | 2004 | struct nouveau_drm *drm = nouveau_drm(dev); |
2055 | struct nvbios *bios = &drm->vbios; | 2005 | struct nouveau_bios *bios = nouveau_bios(drm->device); |
2056 | 2006 | struct nvbios *legacy = &drm->vbios; | |
2057 | memset(bios, 0, sizeof(struct nvbios)); | 2007 | |
2058 | spin_lock_init(&bios->lock); | 2008 | memset(legacy, 0, sizeof(struct nvbios)); |
2059 | bios->dev = dev; | 2009 | spin_lock_init(&legacy->lock); |
2060 | 2010 | legacy->dev = dev; | |
2061 | bios->data = nouveau_bios(drm->device)->data; | 2011 | |
2062 | bios->length = nouveau_bios(drm->device)->size; | 2012 | legacy->data = bios->data; |
2063 | return true; | 2013 | legacy->length = bios->size; |
2064 | } | 2014 | legacy->major_version = bios->version.major; |
2015 | legacy->chip_version = bios->version.chip; | ||
2016 | if (bios->bit_offset) { | ||
2017 | legacy->type = NVBIOS_BIT; | ||
2018 | legacy->offset = bios->bit_offset; | ||
2019 | return !parse_bit_structure(legacy, legacy->offset + 6); | ||
2020 | } else | ||
2021 | if (bios->bmp_offset) { | ||
2022 | legacy->type = NVBIOS_BMP; | ||
2023 | legacy->offset = bios->bmp_offset; | ||
2024 | return !parse_bmp_structure(dev, legacy, legacy->offset); | ||
2025 | } | ||
2065 | 2026 | ||
2066 | static int nouveau_parse_vbios_struct(struct drm_device *dev) | 2027 | return false; |
2067 | { | ||
2068 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
2069 | struct nvbios *bios = &drm->vbios; | ||
2070 | const uint8_t bit_signature[] = { 0xff, 0xb8, 'B', 'I', 'T' }; | ||
2071 | const uint8_t bmp_signature[] = { 0xff, 0x7f, 'N', 'V', 0x0 }; | ||
2072 | int offset; | ||
2073 | |||
2074 | offset = findstr(bios->data, bios->length, | ||
2075 | bit_signature, sizeof(bit_signature)); | ||
2076 | if (offset) { | ||
2077 | NV_INFO(drm, "BIT BIOS found\n"); | ||
2078 | bios->type = NVBIOS_BIT; | ||
2079 | bios->offset = offset; | ||
2080 | return parse_bit_structure(bios, offset + 6); | ||
2081 | } | ||
2082 | |||
2083 | offset = findstr(bios->data, bios->length, | ||
2084 | bmp_signature, sizeof(bmp_signature)); | ||
2085 | if (offset) { | ||
2086 | NV_INFO(drm, "BMP BIOS found\n"); | ||
2087 | bios->type = NVBIOS_BMP; | ||
2088 | bios->offset = offset; | ||
2089 | return parse_bmp_structure(dev, bios, offset); | ||
2090 | } | ||
2091 | |||
2092 | NV_ERROR(drm, "No known BIOS signature found\n"); | ||
2093 | return -ENODEV; | ||
2094 | } | 2028 | } |
2095 | 2029 | ||
2096 | int | 2030 | int |
@@ -2146,10 +2080,6 @@ nouveau_bios_init(struct drm_device *dev) | |||
2146 | if (!NVInitVBIOS(dev)) | 2080 | if (!NVInitVBIOS(dev)) |
2147 | return -ENODEV; | 2081 | return -ENODEV; |
2148 | 2082 | ||
2149 | ret = nouveau_parse_vbios_struct(dev); | ||
2150 | if (ret) | ||
2151 | return ret; | ||
2152 | |||
2153 | ret = parse_dcb_table(dev, bios); | 2083 | ret = parse_dcb_table(dev, bios); |
2154 | if (ret) | 2084 | if (ret) |
2155 | return ret; | 2085 | return ret; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index f68c54ca422f..7ccd28f11adf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h | |||
@@ -107,20 +107,10 @@ struct nvbios { | |||
107 | bool old_style_init; | 107 | bool old_style_init; |
108 | uint16_t init_script_tbls_ptr; | 108 | uint16_t init_script_tbls_ptr; |
109 | uint16_t extra_init_script_tbl_ptr; | 109 | uint16_t extra_init_script_tbl_ptr; |
110 | uint16_t macro_index_tbl_ptr; | 110 | |
111 | uint16_t macro_tbl_ptr; | ||
112 | uint16_t condition_tbl_ptr; | ||
113 | uint16_t io_condition_tbl_ptr; | ||
114 | uint16_t io_flag_condition_tbl_ptr; | ||
115 | uint16_t init_function_tbl_ptr; | ||
116 | |||
117 | uint16_t pll_limit_tbl_ptr; | ||
118 | uint16_t ram_restrict_tbl_ptr; | 111 | uint16_t ram_restrict_tbl_ptr; |
119 | uint8_t ram_restrict_group_count; | 112 | uint8_t ram_restrict_group_count; |
120 | 113 | ||
121 | uint16_t some_script_ptr; /* BIT I + 14 */ | ||
122 | uint16_t init96_tbl_ptr; /* BIT I + 16 */ | ||
123 | |||
124 | struct dcb_table dcb; | 114 | struct dcb_table dcb; |
125 | 115 | ||
126 | struct { | 116 | struct { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 2f2741483b51..11ca82148edc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
@@ -562,7 +562,7 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, | |||
562 | struct nouveau_fence *fence = NULL; | 562 | struct nouveau_fence *fence = NULL; |
563 | int ret; | 563 | int ret; |
564 | 564 | ||
565 | ret = nouveau_fence_new(chan, &fence); | 565 | ret = nouveau_fence_new(chan, false, &fence); |
566 | if (ret) | 566 | if (ret) |
567 | return ret; | 567 | return ret; |
568 | 568 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 174300b6a02e..eaa80a2b81ee 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c | |||
@@ -51,14 +51,15 @@ nouveau_channel_idle(struct nouveau_channel *chan) | |||
51 | struct nouveau_fence *fence = NULL; | 51 | struct nouveau_fence *fence = NULL; |
52 | int ret; | 52 | int ret; |
53 | 53 | ||
54 | ret = nouveau_fence_new(chan, &fence); | 54 | ret = nouveau_fence_new(chan, false, &fence); |
55 | if (!ret) { | 55 | if (!ret) { |
56 | ret = nouveau_fence_wait(fence, false, false); | 56 | ret = nouveau_fence_wait(fence, false, false); |
57 | nouveau_fence_unref(&fence); | 57 | nouveau_fence_unref(&fence); |
58 | } | 58 | } |
59 | 59 | ||
60 | if (ret) | 60 | if (ret) |
61 | NV_ERROR(cli, "failed to idle channel 0x%08x\n", chan->handle); | 61 | NV_ERROR(cli, "failed to idle channel 0x%08x [%s]\n", |
62 | chan->handle, cli->base.name); | ||
62 | return ret; | 63 | return ret; |
63 | } | 64 | } |
64 | 65 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index e620ba8271b4..4dd7ae2ac6c6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c | |||
@@ -55,8 +55,6 @@ MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)"); | |||
55 | static int nouveau_duallink = 1; | 55 | static int nouveau_duallink = 1; |
56 | module_param_named(duallink, nouveau_duallink, int, 0400); | 56 | module_param_named(duallink, nouveau_duallink, int, 0400); |
57 | 57 | ||
58 | static void nouveau_connector_hotplug(void *, int); | ||
59 | |||
60 | struct nouveau_encoder * | 58 | struct nouveau_encoder * |
61 | find_encoder(struct drm_connector *connector, int type) | 59 | find_encoder(struct drm_connector *connector, int type) |
62 | { | 60 | { |
@@ -100,22 +98,6 @@ static void | |||
100 | nouveau_connector_destroy(struct drm_connector *connector) | 98 | nouveau_connector_destroy(struct drm_connector *connector) |
101 | { | 99 | { |
102 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | 100 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
103 | struct nouveau_gpio *gpio; | ||
104 | struct nouveau_drm *drm; | ||
105 | struct drm_device *dev; | ||
106 | |||
107 | if (!nv_connector) | ||
108 | return; | ||
109 | |||
110 | dev = nv_connector->base.dev; | ||
111 | drm = nouveau_drm(dev); | ||
112 | gpio = nouveau_gpio(drm->device); | ||
113 | |||
114 | if (gpio && nv_connector->hpd != DCB_GPIO_UNUSED) { | ||
115 | gpio->isr_del(gpio, 0, nv_connector->hpd, 0xff, | ||
116 | nouveau_connector_hotplug, connector); | ||
117 | } | ||
118 | |||
119 | kfree(nv_connector->edid); | 101 | kfree(nv_connector->edid); |
120 | drm_sysfs_connector_remove(connector); | 102 | drm_sysfs_connector_remove(connector); |
121 | drm_connector_cleanup(connector); | 103 | drm_connector_cleanup(connector); |
@@ -130,7 +112,6 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, | |||
130 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | 112 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
131 | struct nouveau_drm *drm = nouveau_drm(dev); | 113 | struct nouveau_drm *drm = nouveau_drm(dev); |
132 | struct nouveau_gpio *gpio = nouveau_gpio(drm->device); | 114 | struct nouveau_gpio *gpio = nouveau_gpio(drm->device); |
133 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | ||
134 | struct nouveau_i2c_port *port = NULL; | 115 | struct nouveau_i2c_port *port = NULL; |
135 | int i, panel = -ENODEV; | 116 | int i, panel = -ENODEV; |
136 | 117 | ||
@@ -160,8 +141,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, | |||
160 | continue; | 141 | continue; |
161 | nv_encoder = nouveau_encoder(obj_to_encoder(obj)); | 142 | nv_encoder = nouveau_encoder(obj_to_encoder(obj)); |
162 | 143 | ||
163 | if (nv_encoder->dcb->i2c_index < 0xf) | 144 | port = nv_encoder->i2c; |
164 | port = i2c->find(i2c, nv_encoder->dcb->i2c_index); | ||
165 | if (port && nv_probe_i2c(port, 0x50)) { | 145 | if (port && nv_probe_i2c(port, 0x50)) { |
166 | *pnv_encoder = nv_encoder; | 146 | *pnv_encoder = nv_encoder; |
167 | break; | 147 | break; |
@@ -399,9 +379,10 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force) | |||
399 | struct edid *edid = | 379 | struct edid *edid = |
400 | (struct edid *)nouveau_bios_embedded_edid(dev); | 380 | (struct edid *)nouveau_bios_embedded_edid(dev); |
401 | if (edid) { | 381 | if (edid) { |
402 | nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL); | 382 | nv_connector->edid = |
403 | *(nv_connector->edid) = *edid; | 383 | kmemdup(edid, EDID_LENGTH, GFP_KERNEL); |
404 | status = connector_status_connected; | 384 | if (nv_connector->edid) |
385 | status = connector_status_connected; | ||
405 | } | 386 | } |
406 | } | 387 | } |
407 | 388 | ||
@@ -911,6 +892,37 @@ nouveau_connector_funcs_lvds = { | |||
911 | .force = nouveau_connector_force | 892 | .force = nouveau_connector_force |
912 | }; | 893 | }; |
913 | 894 | ||
895 | static void | ||
896 | nouveau_connector_hotplug_work(struct work_struct *work) | ||
897 | { | ||
898 | struct nouveau_connector *nv_connector = | ||
899 | container_of(work, struct nouveau_connector, hpd_work); | ||
900 | struct drm_connector *connector = &nv_connector->base; | ||
901 | struct drm_device *dev = connector->dev; | ||
902 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
903 | struct nouveau_gpio *gpio = nouveau_gpio(drm->device); | ||
904 | bool plugged = gpio->get(gpio, 0, nv_connector->hpd.func, 0xff); | ||
905 | |||
906 | NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", | ||
907 | drm_get_connector_name(connector)); | ||
908 | |||
909 | if (plugged) | ||
910 | drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); | ||
911 | else | ||
912 | drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); | ||
913 | |||
914 | drm_helper_hpd_irq_event(dev); | ||
915 | } | ||
916 | |||
917 | static int | ||
918 | nouveau_connector_hotplug(struct nouveau_eventh *event, int index) | ||
919 | { | ||
920 | struct nouveau_connector *nv_connector = | ||
921 | container_of(event, struct nouveau_connector, hpd_func); | ||
922 | schedule_work(&nv_connector->hpd_work); | ||
923 | return NVKM_EVENT_KEEP; | ||
924 | } | ||
925 | |||
914 | static int | 926 | static int |
915 | drm_conntype_from_dcb(enum dcb_connector_type dcb) | 927 | drm_conntype_from_dcb(enum dcb_connector_type dcb) |
916 | { | 928 | { |
@@ -961,6 +973,7 @@ nouveau_connector_create(struct drm_device *dev, int index) | |||
961 | return ERR_PTR(-ENOMEM); | 973 | return ERR_PTR(-ENOMEM); |
962 | 974 | ||
963 | connector = &nv_connector->base; | 975 | connector = &nv_connector->base; |
976 | INIT_WORK(&nv_connector->hpd_work, nouveau_connector_hotplug_work); | ||
964 | nv_connector->index = index; | 977 | nv_connector->index = index; |
965 | 978 | ||
966 | /* attempt to parse vbios connector type and hotplug gpio */ | 979 | /* attempt to parse vbios connector type and hotplug gpio */ |
@@ -975,8 +988,11 @@ nouveau_connector_create(struct drm_device *dev, int index) | |||
975 | if (olddcb_conntab(dev)[3] >= 4) | 988 | if (olddcb_conntab(dev)[3] >= 4) |
976 | entry |= (u32)ROM16(nv_connector->dcb[2]) << 16; | 989 | entry |= (u32)ROM16(nv_connector->dcb[2]) << 16; |
977 | 990 | ||
978 | nv_connector->hpd = ffs((entry & 0x07033000) >> 12); | 991 | ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)], |
979 | nv_connector->hpd = hpd[nv_connector->hpd]; | 992 | DCB_GPIO_UNUSED, &nv_connector->hpd); |
993 | nv_connector->hpd_func.func = nouveau_connector_hotplug; | ||
994 | if (ret) | ||
995 | nv_connector->hpd.func = DCB_GPIO_UNUSED; | ||
980 | 996 | ||
981 | nv_connector->type = nv_connector->dcb[0]; | 997 | nv_connector->type = nv_connector->dcb[0]; |
982 | if (drm_conntype_from_dcb(nv_connector->type) == | 998 | if (drm_conntype_from_dcb(nv_connector->type) == |
@@ -999,7 +1015,7 @@ nouveau_connector_create(struct drm_device *dev, int index) | |||
999 | } | 1015 | } |
1000 | } else { | 1016 | } else { |
1001 | nv_connector->type = DCB_CONNECTOR_NONE; | 1017 | nv_connector->type = DCB_CONNECTOR_NONE; |
1002 | nv_connector->hpd = DCB_GPIO_UNUSED; | 1018 | nv_connector->hpd.func = DCB_GPIO_UNUSED; |
1003 | } | 1019 | } |
1004 | 1020 | ||
1005 | /* no vbios data, or an unknown dcb connector type - attempt to | 1021 | /* no vbios data, or an unknown dcb connector type - attempt to |
@@ -1126,31 +1142,9 @@ nouveau_connector_create(struct drm_device *dev, int index) | |||
1126 | } | 1142 | } |
1127 | 1143 | ||
1128 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; | 1144 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
1129 | if (gpio && nv_connector->hpd != DCB_GPIO_UNUSED) { | 1145 | if (nv_connector->hpd.func != DCB_GPIO_UNUSED) |
1130 | ret = gpio->isr_add(gpio, 0, nv_connector->hpd, 0xff, | 1146 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
1131 | nouveau_connector_hotplug, connector); | ||
1132 | if (ret == 0) | ||
1133 | connector->polled = DRM_CONNECTOR_POLL_HPD; | ||
1134 | } | ||
1135 | 1147 | ||
1136 | drm_sysfs_connector_add(connector); | 1148 | drm_sysfs_connector_add(connector); |
1137 | return connector; | 1149 | return connector; |
1138 | } | 1150 | } |
1139 | |||
1140 | static void | ||
1141 | nouveau_connector_hotplug(void *data, int plugged) | ||
1142 | { | ||
1143 | struct drm_connector *connector = data; | ||
1144 | struct drm_device *dev = connector->dev; | ||
1145 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
1146 | |||
1147 | NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", | ||
1148 | drm_get_connector_name(connector)); | ||
1149 | |||
1150 | if (plugged) | ||
1151 | drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); | ||
1152 | else | ||
1153 | drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); | ||
1154 | |||
1155 | drm_helper_hpd_irq_event(dev); | ||
1156 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 20eb84cce9e6..6e399aad491a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h | |||
@@ -30,6 +30,11 @@ | |||
30 | #include <drm/drm_edid.h> | 30 | #include <drm/drm_edid.h> |
31 | #include "nouveau_crtc.h" | 31 | #include "nouveau_crtc.h" |
32 | 32 | ||
33 | #include <core/event.h> | ||
34 | |||
35 | #include <subdev/bios.h> | ||
36 | #include <subdev/bios/gpio.h> | ||
37 | |||
33 | struct nouveau_i2c_port; | 38 | struct nouveau_i2c_port; |
34 | 39 | ||
35 | enum nouveau_underscan_type { | 40 | enum nouveau_underscan_type { |
@@ -61,7 +66,10 @@ struct nouveau_connector { | |||
61 | enum dcb_connector_type type; | 66 | enum dcb_connector_type type; |
62 | u8 index; | 67 | u8 index; |
63 | u8 *dcb; | 68 | u8 *dcb; |
64 | u8 hpd; | 69 | |
70 | struct dcb_gpio_func hpd; | ||
71 | struct work_struct hpd_work; | ||
72 | struct nouveau_eventh hpd_func; | ||
65 | 73 | ||
66 | int dithering_mode; | 74 | int dithering_mode; |
67 | int dithering_depth; | 75 | int dithering_depth; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index d42c9e860c16..4610c3a29bbe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -41,6 +41,8 @@ | |||
41 | #include <subdev/gpio.h> | 41 | #include <subdev/gpio.h> |
42 | #include <engine/disp.h> | 42 | #include <engine/disp.h> |
43 | 43 | ||
44 | #include <core/class.h> | ||
45 | |||
44 | static void | 46 | static void |
45 | nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) | 47 | nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) |
46 | { | 48 | { |
@@ -231,8 +233,10 @@ nouveau_display_init(struct drm_device *dev) | |||
231 | /* enable hotplug interrupts */ | 233 | /* enable hotplug interrupts */ |
232 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 234 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
233 | struct nouveau_connector *conn = nouveau_connector(connector); | 235 | struct nouveau_connector *conn = nouveau_connector(connector); |
234 | if (gpio) | 236 | if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) { |
235 | gpio->irq(gpio, 0, conn->hpd, 0xff, true); | 237 | nouveau_event_get(gpio->events, conn->hpd.line, |
238 | &conn->hpd_func); | ||
239 | } | ||
236 | } | 240 | } |
237 | 241 | ||
238 | return ret; | 242 | return ret; |
@@ -249,37 +253,20 @@ nouveau_display_fini(struct drm_device *dev) | |||
249 | /* disable hotplug interrupts */ | 253 | /* disable hotplug interrupts */ |
250 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 254 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
251 | struct nouveau_connector *conn = nouveau_connector(connector); | 255 | struct nouveau_connector *conn = nouveau_connector(connector); |
252 | if (gpio) | 256 | if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) { |
253 | gpio->irq(gpio, 0, conn->hpd, 0xff, false); | 257 | nouveau_event_put(gpio->events, conn->hpd.line, |
258 | &conn->hpd_func); | ||
259 | } | ||
254 | } | 260 | } |
255 | 261 | ||
256 | drm_kms_helper_poll_disable(dev); | 262 | drm_kms_helper_poll_disable(dev); |
257 | disp->fini(dev); | 263 | disp->fini(dev); |
258 | } | 264 | } |
259 | 265 | ||
260 | static void | ||
261 | nouveau_display_vblank_notify(void *data, int crtc) | ||
262 | { | ||
263 | drm_handle_vblank(data, crtc); | ||
264 | } | ||
265 | |||
266 | static void | ||
267 | nouveau_display_vblank_get(void *data, int crtc) | ||
268 | { | ||
269 | drm_vblank_get(data, crtc); | ||
270 | } | ||
271 | |||
272 | static void | ||
273 | nouveau_display_vblank_put(void *data, int crtc) | ||
274 | { | ||
275 | drm_vblank_put(data, crtc); | ||
276 | } | ||
277 | |||
278 | int | 266 | int |
279 | nouveau_display_create(struct drm_device *dev) | 267 | nouveau_display_create(struct drm_device *dev) |
280 | { | 268 | { |
281 | struct nouveau_drm *drm = nouveau_drm(dev); | 269 | struct nouveau_drm *drm = nouveau_drm(dev); |
282 | struct nouveau_disp *pdisp = nouveau_disp(drm->device); | ||
283 | struct nouveau_display *disp; | 270 | struct nouveau_display *disp; |
284 | u32 pclass = dev->pdev->class >> 8; | 271 | u32 pclass = dev->pdev->class >> 8; |
285 | int ret, gen; | 272 | int ret, gen; |
@@ -288,11 +275,6 @@ nouveau_display_create(struct drm_device *dev) | |||
288 | if (!disp) | 275 | if (!disp) |
289 | return -ENOMEM; | 276 | return -ENOMEM; |
290 | 277 | ||
291 | pdisp->vblank.data = dev; | ||
292 | pdisp->vblank.notify = nouveau_display_vblank_notify; | ||
293 | pdisp->vblank.get = nouveau_display_vblank_get; | ||
294 | pdisp->vblank.put = nouveau_display_vblank_put; | ||
295 | |||
296 | drm_mode_config_init(dev); | 278 | drm_mode_config_init(dev); |
297 | drm_mode_create_scaling_mode_property(dev); | 279 | drm_mode_create_scaling_mode_property(dev); |
298 | drm_mode_create_dvi_i_properties(dev); | 280 | drm_mode_create_dvi_i_properties(dev); |
@@ -316,17 +298,13 @@ nouveau_display_create(struct drm_device *dev) | |||
316 | drm_property_create_range(dev, 0, "underscan vborder", 0, 128); | 298 | drm_property_create_range(dev, 0, "underscan vborder", 0, 128); |
317 | 299 | ||
318 | if (gen >= 1) { | 300 | if (gen >= 1) { |
301 | /* -90..+90 */ | ||
319 | disp->vibrant_hue_property = | 302 | disp->vibrant_hue_property = |
320 | drm_property_create(dev, DRM_MODE_PROP_RANGE, | 303 | drm_property_create_range(dev, 0, "vibrant hue", 0, 180); |
321 | "vibrant hue", 2); | ||
322 | disp->vibrant_hue_property->values[0] = 0; | ||
323 | disp->vibrant_hue_property->values[1] = 180; /* -90..+90 */ | ||
324 | 304 | ||
305 | /* -100..+100 */ | ||
325 | disp->color_vibrance_property = | 306 | disp->color_vibrance_property = |
326 | drm_property_create(dev, DRM_MODE_PROP_RANGE, | 307 | drm_property_create_range(dev, 0, "color vibrance", 0, 200); |
327 | "color vibrance", 2); | ||
328 | disp->color_vibrance_property->values[0] = 0; | ||
329 | disp->color_vibrance_property->values[1] = 200; /* -100..+100 */ | ||
330 | } | 308 | } |
331 | 309 | ||
332 | dev->mode_config.funcs = &nouveau_mode_config_funcs; | 310 | dev->mode_config.funcs = &nouveau_mode_config_funcs; |
@@ -478,39 +456,6 @@ nouveau_display_resume(struct drm_device *dev) | |||
478 | } | 456 | } |
479 | } | 457 | } |
480 | 458 | ||
481 | int | ||
482 | nouveau_vblank_enable(struct drm_device *dev, int crtc) | ||
483 | { | ||
484 | struct nouveau_device *device = nouveau_dev(dev); | ||
485 | |||
486 | if (device->card_type >= NV_D0) | ||
487 | nv_mask(device, 0x6100c0 + (crtc * 0x800), 1, 1); | ||
488 | else | ||
489 | if (device->card_type >= NV_50) | ||
490 | nv_mask(device, NV50_PDISPLAY_INTR_EN_1, 0, | ||
491 | NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc)); | ||
492 | else | ||
493 | NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, | ||
494 | NV_PCRTC_INTR_0_VBLANK); | ||
495 | |||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | void | ||
500 | nouveau_vblank_disable(struct drm_device *dev, int crtc) | ||
501 | { | ||
502 | struct nouveau_device *device = nouveau_dev(dev); | ||
503 | |||
504 | if (device->card_type >= NV_D0) | ||
505 | nv_mask(device, 0x6100c0 + (crtc * 0x800), 1, 0); | ||
506 | else | ||
507 | if (device->card_type >= NV_50) | ||
508 | nv_mask(device, NV50_PDISPLAY_INTR_EN_1, | ||
509 | NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0); | ||
510 | else | ||
511 | NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0); | ||
512 | } | ||
513 | |||
514 | static int | 459 | static int |
515 | nouveau_page_flip_reserve(struct nouveau_bo *old_bo, | 460 | nouveau_page_flip_reserve(struct nouveau_bo *old_bo, |
516 | struct nouveau_bo *new_bo) | 461 | struct nouveau_bo *new_bo) |
@@ -595,7 +540,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, | |||
595 | } | 540 | } |
596 | FIRE_RING (chan); | 541 | FIRE_RING (chan); |
597 | 542 | ||
598 | ret = nouveau_fence_new(chan, pfence); | 543 | ret = nouveau_fence_new(chan, false, pfence); |
599 | if (ret) | 544 | if (ret) |
600 | goto fail; | 545 | goto fail; |
601 | 546 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 722548bb3bd3..1ea3e4734b62 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h | |||
@@ -59,9 +59,6 @@ void nouveau_display_fini(struct drm_device *dev); | |||
59 | int nouveau_display_suspend(struct drm_device *dev); | 59 | int nouveau_display_suspend(struct drm_device *dev); |
60 | void nouveau_display_resume(struct drm_device *dev); | 60 | void nouveau_display_resume(struct drm_device *dev); |
61 | 61 | ||
62 | int nouveau_vblank_enable(struct drm_device *dev, int crtc); | ||
63 | void nouveau_vblank_disable(struct drm_device *dev, int crtc); | ||
64 | |||
65 | int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | 62 | int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, |
66 | struct drm_pending_vblank_event *event); | 63 | struct drm_pending_vblank_event *event); |
67 | int nouveau_finish_page_flip(struct nouveau_channel *, | 64 | int nouveau_finish_page_flip(struct nouveau_channel *, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index 5c2e22932d1c..690d5930ce32 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h | |||
@@ -191,7 +191,7 @@ WIND_RING(struct nouveau_channel *chan) | |||
191 | #define NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG 0x00000002 | 191 | #define NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG 0x00000002 |
192 | #define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL 0x00000004 | 192 | #define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL 0x00000004 |
193 | #define NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD 0x00001000 | 193 | #define NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD 0x00001000 |
194 | #define NV84_SUBCHAN_NOTIFY_INTR 0x00000020 | 194 | #define NV84_SUBCHAN_UEVENT 0x00000020 |
195 | #define NV84_SUBCHAN_WRCACHE_FLUSH 0x00000024 | 195 | #define NV84_SUBCHAN_WRCACHE_FLUSH 0x00000024 |
196 | #define NV10_SUBCHAN_REF_CNT 0x00000050 | 196 | #define NV10_SUBCHAN_REF_CNT 0x00000050 |
197 | #define NVSW_SUBCHAN_PAGE_FLIP 0x00000054 | 197 | #define NVSW_SUBCHAN_PAGE_FLIP 0x00000054 |
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 59838651ee8f..36fd22500569 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c | |||
@@ -35,300 +35,6 @@ | |||
35 | #include <subdev/gpio.h> | 35 | #include <subdev/gpio.h> |
36 | #include <subdev/i2c.h> | 36 | #include <subdev/i2c.h> |
37 | 37 | ||
38 | /****************************************************************************** | ||
39 | * link training | ||
40 | *****************************************************************************/ | ||
41 | struct dp_state { | ||
42 | struct nouveau_i2c_port *auxch; | ||
43 | struct nouveau_object *core; | ||
44 | struct dcb_output *dcb; | ||
45 | int crtc; | ||
46 | u8 *dpcd; | ||
47 | int link_nr; | ||
48 | u32 link_bw; | ||
49 | u8 stat[6]; | ||
50 | u8 conf[4]; | ||
51 | }; | ||
52 | |||
53 | static void | ||
54 | dp_set_link_config(struct drm_device *dev, struct dp_state *dp) | ||
55 | { | ||
56 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
57 | struct dcb_output *dcb = dp->dcb; | ||
58 | const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1); | ||
59 | const u32 moff = (dp->crtc << 3) | (link << 2) | or; | ||
60 | u8 sink[2]; | ||
61 | u32 data; | ||
62 | |||
63 | NV_DEBUG(drm, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); | ||
64 | |||
65 | /* set desired link configuration on the source */ | ||
66 | data = ((dp->link_bw / 27000) << 8) | dp->link_nr; | ||
67 | if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) | ||
68 | data |= NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH; | ||
69 | |||
70 | nv_call(dp->core, NV94_DISP_SOR_DP_LNKCTL + moff, data); | ||
71 | |||
72 | /* inform the sink of the new configuration */ | ||
73 | sink[0] = dp->link_bw / 27000; | ||
74 | sink[1] = dp->link_nr; | ||
75 | if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) | ||
76 | sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; | ||
77 | |||
78 | nv_wraux(dp->auxch, DP_LINK_BW_SET, sink, 2); | ||
79 | } | ||
80 | |||
81 | static void | ||
82 | dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 pattern) | ||
83 | { | ||
84 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
85 | struct dcb_output *dcb = dp->dcb; | ||
86 | const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1); | ||
87 | const u32 moff = (dp->crtc << 3) | (link << 2) | or; | ||
88 | u8 sink_tp; | ||
89 | |||
90 | NV_DEBUG(drm, "training pattern %d\n", pattern); | ||
91 | |||
92 | nv_call(dp->core, NV94_DISP_SOR_DP_TRAIN + moff, pattern); | ||
93 | |||
94 | nv_rdaux(dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1); | ||
95 | sink_tp &= ~DP_TRAINING_PATTERN_MASK; | ||
96 | sink_tp |= pattern; | ||
97 | nv_wraux(dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1); | ||
98 | } | ||
99 | |||
100 | static int | ||
101 | dp_link_train_commit(struct drm_device *dev, struct dp_state *dp) | ||
102 | { | ||
103 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
104 | struct dcb_output *dcb = dp->dcb; | ||
105 | const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1); | ||
106 | const u32 moff = (dp->crtc << 3) | (link << 2) | or; | ||
107 | int i; | ||
108 | |||
109 | for (i = 0; i < dp->link_nr; i++) { | ||
110 | u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; | ||
111 | u8 lpre = (lane & 0x0c) >> 2; | ||
112 | u8 lvsw = (lane & 0x03) >> 0; | ||
113 | |||
114 | dp->conf[i] = (lpre << 3) | lvsw; | ||
115 | if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200) | ||
116 | dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED; | ||
117 | if ((lpre << 3) == DP_TRAIN_PRE_EMPHASIS_9_5) | ||
118 | dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; | ||
119 | |||
120 | NV_DEBUG(drm, "config lane %d %02x\n", i, dp->conf[i]); | ||
121 | |||
122 | nv_call(dp->core, NV94_DISP_SOR_DP_DRVCTL(i) + moff, (lvsw << 8) | lpre); | ||
123 | } | ||
124 | |||
125 | return nv_wraux(dp->auxch, DP_TRAINING_LANE0_SET, dp->conf, 4); | ||
126 | } | ||
127 | |||
128 | static int | ||
129 | dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay) | ||
130 | { | ||
131 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
132 | int ret; | ||
133 | |||
134 | udelay(delay); | ||
135 | |||
136 | ret = nv_rdaux(dp->auxch, DP_LANE0_1_STATUS, dp->stat, 6); | ||
137 | if (ret) | ||
138 | return ret; | ||
139 | |||
140 | NV_DEBUG(drm, "status %*ph\n", 6, dp->stat); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int | ||
145 | dp_link_train_cr(struct drm_device *dev, struct dp_state *dp) | ||
146 | { | ||
147 | bool cr_done = false, abort = false; | ||
148 | int voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK; | ||
149 | int tries = 0, i; | ||
150 | |||
151 | dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_1); | ||
152 | |||
153 | do { | ||
154 | if (dp_link_train_commit(dev, dp) || | ||
155 | dp_link_train_update(dev, dp, 100)) | ||
156 | break; | ||
157 | |||
158 | cr_done = true; | ||
159 | for (i = 0; i < dp->link_nr; i++) { | ||
160 | u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; | ||
161 | if (!(lane & DP_LANE_CR_DONE)) { | ||
162 | cr_done = false; | ||
163 | if (dp->conf[i] & DP_TRAIN_MAX_SWING_REACHED) | ||
164 | abort = true; | ||
165 | break; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | if ((dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) { | ||
170 | voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK; | ||
171 | tries = 0; | ||
172 | } | ||
173 | } while (!cr_done && !abort && ++tries < 5); | ||
174 | |||
175 | return cr_done ? 0 : -1; | ||
176 | } | ||
177 | |||
178 | static int | ||
179 | dp_link_train_eq(struct drm_device *dev, struct dp_state *dp) | ||
180 | { | ||
181 | bool eq_done, cr_done = true; | ||
182 | int tries = 0, i; | ||
183 | |||
184 | dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_2); | ||
185 | |||
186 | do { | ||
187 | if (dp_link_train_update(dev, dp, 400)) | ||
188 | break; | ||
189 | |||
190 | eq_done = !!(dp->stat[2] & DP_INTERLANE_ALIGN_DONE); | ||
191 | for (i = 0; i < dp->link_nr && eq_done; i++) { | ||
192 | u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; | ||
193 | if (!(lane & DP_LANE_CR_DONE)) | ||
194 | cr_done = false; | ||
195 | if (!(lane & DP_LANE_CHANNEL_EQ_DONE) || | ||
196 | !(lane & DP_LANE_SYMBOL_LOCKED)) | ||
197 | eq_done = false; | ||
198 | } | ||
199 | |||
200 | if (dp_link_train_commit(dev, dp)) | ||
201 | break; | ||
202 | } while (!eq_done && cr_done && ++tries <= 5); | ||
203 | |||
204 | return eq_done ? 0 : -1; | ||
205 | } | ||
206 | |||
207 | static void | ||
208 | dp_link_train_init(struct drm_device *dev, struct dp_state *dp, bool spread) | ||
209 | { | ||
210 | struct dcb_output *dcb = dp->dcb; | ||
211 | const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1); | ||
212 | const u32 moff = (dp->crtc << 3) | (link << 2) | or; | ||
213 | |||
214 | nv_call(dp->core, NV94_DISP_SOR_DP_TRAIN + moff, (spread ? | ||
215 | NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_ON : | ||
216 | NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_OFF) | | ||
217 | NV94_DISP_SOR_DP_TRAIN_OP_INIT); | ||
218 | } | ||
219 | |||
220 | static void | ||
221 | dp_link_train_fini(struct drm_device *dev, struct dp_state *dp) | ||
222 | { | ||
223 | struct dcb_output *dcb = dp->dcb; | ||
224 | const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1); | ||
225 | const u32 moff = (dp->crtc << 3) | (link << 2) | or; | ||
226 | |||
227 | nv_call(dp->core, NV94_DISP_SOR_DP_TRAIN + moff, | ||
228 | NV94_DISP_SOR_DP_TRAIN_OP_FINI); | ||
229 | } | ||
230 | |||
231 | static bool | ||
232 | nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate, | ||
233 | struct nouveau_object *core) | ||
234 | { | ||
235 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
236 | struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); | ||
237 | struct nouveau_connector *nv_connector = | ||
238 | nouveau_encoder_connector_get(nv_encoder); | ||
239 | struct drm_device *dev = encoder->dev; | ||
240 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
241 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | ||
242 | struct nouveau_gpio *gpio = nouveau_gpio(drm->device); | ||
243 | const u32 bw_list[] = { 270000, 162000, 0 }; | ||
244 | const u32 *link_bw = bw_list; | ||
245 | struct dp_state dp; | ||
246 | |||
247 | dp.auxch = i2c->find(i2c, nv_encoder->dcb->i2c_index); | ||
248 | if (!dp.auxch) | ||
249 | return false; | ||
250 | |||
251 | dp.core = core; | ||
252 | dp.dcb = nv_encoder->dcb; | ||
253 | dp.crtc = nv_crtc->index; | ||
254 | dp.dpcd = nv_encoder->dp.dpcd; | ||
255 | |||
256 | /* adjust required bandwidth for 8B/10B coding overhead */ | ||
257 | datarate = (datarate / 8) * 10; | ||
258 | |||
259 | /* some sinks toggle hotplug in response to some of the actions | ||
260 | * we take during link training (DP_SET_POWER is one), we need | ||
261 | * to ignore them for the moment to avoid races. | ||
262 | */ | ||
263 | gpio->irq(gpio, 0, nv_connector->hpd, 0xff, false); | ||
264 | |||
265 | /* enable down-spreading and execute pre-train script from vbios */ | ||
266 | dp_link_train_init(dev, &dp, nv_encoder->dp.dpcd[3] & 1); | ||
267 | |||
268 | /* start off at highest link rate supported by encoder and display */ | ||
269 | while (*link_bw > nv_encoder->dp.link_bw) | ||
270 | link_bw++; | ||
271 | |||
272 | while (link_bw[0]) { | ||
273 | /* find minimum required lane count at this link rate */ | ||
274 | dp.link_nr = nv_encoder->dp.link_nr; | ||
275 | while ((dp.link_nr >> 1) * link_bw[0] > datarate) | ||
276 | dp.link_nr >>= 1; | ||
277 | |||
278 | /* drop link rate to minimum with this lane count */ | ||
279 | while ((link_bw[1] * dp.link_nr) > datarate) | ||
280 | link_bw++; | ||
281 | dp.link_bw = link_bw[0]; | ||
282 | |||
283 | /* program selected link configuration */ | ||
284 | dp_set_link_config(dev, &dp); | ||
285 | |||
286 | /* attempt to train the link at this configuration */ | ||
287 | memset(dp.stat, 0x00, sizeof(dp.stat)); | ||
288 | if (!dp_link_train_cr(dev, &dp) && | ||
289 | !dp_link_train_eq(dev, &dp)) | ||
290 | break; | ||
291 | |||
292 | /* retry at lower rate */ | ||
293 | link_bw++; | ||
294 | } | ||
295 | |||
296 | /* finish link training */ | ||
297 | dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE); | ||
298 | |||
299 | /* execute post-train script from vbios */ | ||
300 | dp_link_train_fini(dev, &dp); | ||
301 | |||
302 | /* re-enable hotplug detect */ | ||
303 | gpio->irq(gpio, 0, nv_connector->hpd, 0xff, true); | ||
304 | return true; | ||
305 | } | ||
306 | |||
307 | void | ||
308 | nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate, | ||
309 | struct nouveau_object *core) | ||
310 | { | ||
311 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
312 | struct nouveau_drm *drm = nouveau_drm(encoder->dev); | ||
313 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | ||
314 | struct nouveau_i2c_port *auxch; | ||
315 | u8 status; | ||
316 | |||
317 | auxch = i2c->find(i2c, nv_encoder->dcb->i2c_index); | ||
318 | if (!auxch) | ||
319 | return; | ||
320 | |||
321 | if (mode == DRM_MODE_DPMS_ON) | ||
322 | status = DP_SET_POWER_D0; | ||
323 | else | ||
324 | status = DP_SET_POWER_D3; | ||
325 | |||
326 | nv_wraux(auxch, DP_SET_POWER, &status, 1); | ||
327 | |||
328 | if (mode == DRM_MODE_DPMS_ON) | ||
329 | nouveau_dp_link_train(encoder, datarate, core); | ||
330 | } | ||
331 | |||
332 | static void | 38 | static void |
333 | nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch, | 39 | nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch, |
334 | u8 *dpcd) | 40 | u8 *dpcd) |
@@ -355,12 +61,11 @@ nouveau_dp_detect(struct drm_encoder *encoder) | |||
355 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | 61 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
356 | struct drm_device *dev = encoder->dev; | 62 | struct drm_device *dev = encoder->dev; |
357 | struct nouveau_drm *drm = nouveau_drm(dev); | 63 | struct nouveau_drm *drm = nouveau_drm(dev); |
358 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | ||
359 | struct nouveau_i2c_port *auxch; | 64 | struct nouveau_i2c_port *auxch; |
360 | u8 *dpcd = nv_encoder->dp.dpcd; | 65 | u8 *dpcd = nv_encoder->dp.dpcd; |
361 | int ret; | 66 | int ret; |
362 | 67 | ||
363 | auxch = i2c->find(i2c, nv_encoder->dcb->i2c_index); | 68 | auxch = nv_encoder->i2c; |
364 | if (!auxch) | 69 | if (!auxch) |
365 | return false; | 70 | return false; |
366 | 71 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 8e8e8ce75528..ccfe2be3ae38 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include <subdev/device.h> | 34 | #include <subdev/device.h> |
35 | #include <subdev/vm.h> | 35 | #include <subdev/vm.h> |
36 | 36 | ||
37 | #include <engine/disp.h> | ||
38 | |||
37 | #include "nouveau_drm.h" | 39 | #include "nouveau_drm.h" |
38 | #include "nouveau_irq.h" | 40 | #include "nouveau_irq.h" |
39 | #include "nouveau_dma.h" | 41 | #include "nouveau_dma.h" |
@@ -68,6 +70,32 @@ module_param_named(modeset, nouveau_modeset, int, 0400); | |||
68 | 70 | ||
69 | static struct drm_driver driver; | 71 | static struct drm_driver driver; |
70 | 72 | ||
73 | static int | ||
74 | nouveau_drm_vblank_enable(struct drm_device *dev, int head) | ||
75 | { | ||
76 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
77 | struct nouveau_disp *pdisp = nouveau_disp(drm->device); | ||
78 | nouveau_event_get(pdisp->vblank, head, &drm->vblank); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static void | ||
83 | nouveau_drm_vblank_disable(struct drm_device *dev, int head) | ||
84 | { | ||
85 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
86 | struct nouveau_disp *pdisp = nouveau_disp(drm->device); | ||
87 | nouveau_event_put(pdisp->vblank, head, &drm->vblank); | ||
88 | } | ||
89 | |||
90 | static int | ||
91 | nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head) | ||
92 | { | ||
93 | struct nouveau_drm *drm = | ||
94 | container_of(event, struct nouveau_drm, vblank); | ||
95 | drm_handle_vblank(drm->dev, head); | ||
96 | return NVKM_EVENT_KEEP; | ||
97 | } | ||
98 | |||
71 | static u64 | 99 | static u64 |
72 | nouveau_name(struct pci_dev *pdev) | 100 | nouveau_name(struct pci_dev *pdev) |
73 | { | 101 | { |
@@ -132,7 +160,8 @@ nouveau_accel_init(struct nouveau_drm *drm) | |||
132 | 160 | ||
133 | /* initialise synchronisation routines */ | 161 | /* initialise synchronisation routines */ |
134 | if (device->card_type < NV_10) ret = nv04_fence_create(drm); | 162 | if (device->card_type < NV_10) ret = nv04_fence_create(drm); |
135 | else if (device->card_type < NV_50) ret = nv10_fence_create(drm); | 163 | else if (device->chipset < 0x17) ret = nv10_fence_create(drm); |
164 | else if (device->card_type < NV_50) ret = nv17_fence_create(drm); | ||
136 | else if (device->chipset < 0x84) ret = nv50_fence_create(drm); | 165 | else if (device->chipset < 0x84) ret = nv50_fence_create(drm); |
137 | else if (device->card_type < NV_C0) ret = nv84_fence_create(drm); | 166 | else if (device->card_type < NV_C0) ret = nv84_fence_create(drm); |
138 | else ret = nvc0_fence_create(drm); | 167 | else ret = nvc0_fence_create(drm); |
@@ -259,6 +288,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
259 | 288 | ||
260 | dev->dev_private = drm; | 289 | dev->dev_private = drm; |
261 | drm->dev = dev; | 290 | drm->dev = dev; |
291 | drm->vblank.func = nouveau_drm_vblank_handler; | ||
262 | 292 | ||
263 | INIT_LIST_HEAD(&drm->clients); | 293 | INIT_LIST_HEAD(&drm->clients); |
264 | spin_lock_init(&drm->tile.lock); | 294 | spin_lock_init(&drm->tile.lock); |
@@ -398,7 +428,7 @@ nouveau_drm_remove(struct pci_dev *pdev) | |||
398 | nouveau_object_debug(); | 428 | nouveau_object_debug(); |
399 | } | 429 | } |
400 | 430 | ||
401 | int | 431 | static int |
402 | nouveau_do_suspend(struct drm_device *dev) | 432 | nouveau_do_suspend(struct drm_device *dev) |
403 | { | 433 | { |
404 | struct nouveau_drm *drm = nouveau_drm(dev); | 434 | struct nouveau_drm *drm = nouveau_drm(dev); |
@@ -469,7 +499,7 @@ int nouveau_pmops_suspend(struct device *dev) | |||
469 | return 0; | 499 | return 0; |
470 | } | 500 | } |
471 | 501 | ||
472 | int | 502 | static int |
473 | nouveau_do_resume(struct drm_device *dev) | 503 | nouveau_do_resume(struct drm_device *dev) |
474 | { | 504 | { |
475 | struct nouveau_drm *drm = nouveau_drm(dev); | 505 | struct nouveau_drm *drm = nouveau_drm(dev); |
@@ -543,10 +573,11 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) | |||
543 | struct pci_dev *pdev = dev->pdev; | 573 | struct pci_dev *pdev = dev->pdev; |
544 | struct nouveau_drm *drm = nouveau_drm(dev); | 574 | struct nouveau_drm *drm = nouveau_drm(dev); |
545 | struct nouveau_cli *cli; | 575 | struct nouveau_cli *cli; |
546 | char name[16]; | 576 | char name[32], tmpname[TASK_COMM_LEN]; |
547 | int ret; | 577 | int ret; |
548 | 578 | ||
549 | snprintf(name, sizeof(name), "%d", pid_nr(fpriv->pid)); | 579 | get_task_comm(tmpname, current); |
580 | snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid)); | ||
550 | 581 | ||
551 | ret = nouveau_cli_create(pdev, name, sizeof(*cli), (void **)&cli); | 582 | ret = nouveau_cli_create(pdev, name, sizeof(*cli), (void **)&cli); |
552 | if (ret) | 583 | if (ret) |
@@ -642,8 +673,8 @@ driver = { | |||
642 | .irq_handler = nouveau_irq_handler, | 673 | .irq_handler = nouveau_irq_handler, |
643 | 674 | ||
644 | .get_vblank_counter = drm_vblank_count, | 675 | .get_vblank_counter = drm_vblank_count, |
645 | .enable_vblank = nouveau_vblank_enable, | 676 | .enable_vblank = nouveau_drm_vblank_enable, |
646 | .disable_vblank = nouveau_vblank_disable, | 677 | .disable_vblank = nouveau_drm_vblank_disable, |
647 | 678 | ||
648 | .ioctls = nouveau_ioctls, | 679 | .ioctls = nouveau_ioctls, |
649 | .fops = &nouveau_driver_fops, | 680 | .fops = &nouveau_driver_fops, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index aa89eb938b47..b25df374c901 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #define DRIVER_PATCHLEVEL 0 | 13 | #define DRIVER_PATCHLEVEL 0 |
14 | 14 | ||
15 | #include <core/client.h> | 15 | #include <core/client.h> |
16 | #include <core/event.h> | ||
16 | 17 | ||
17 | #include <subdev/vm.h> | 18 | #include <subdev/vm.h> |
18 | 19 | ||
@@ -112,6 +113,7 @@ struct nouveau_drm { | |||
112 | struct nvbios vbios; | 113 | struct nvbios vbios; |
113 | struct nouveau_display *display; | 114 | struct nouveau_display *display; |
114 | struct backlight_device *backlight; | 115 | struct backlight_device *backlight; |
116 | struct nouveau_eventh vblank; | ||
115 | 117 | ||
116 | /* power management */ | 118 | /* power management */ |
117 | struct nouveau_pm *pm; | 119 | struct nouveau_pm *pm; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index d0d95bd511ab..e24341229d5e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h | |||
@@ -36,19 +36,12 @@ | |||
36 | 36 | ||
37 | struct nouveau_i2c_port; | 37 | struct nouveau_i2c_port; |
38 | 38 | ||
39 | struct dp_train_func { | ||
40 | void (*link_set)(struct drm_device *, struct dcb_output *, int crtc, | ||
41 | int nr, u32 bw, bool enhframe); | ||
42 | void (*train_set)(struct drm_device *, struct dcb_output *, u8 pattern); | ||
43 | void (*train_adj)(struct drm_device *, struct dcb_output *, | ||
44 | u8 lane, u8 swing, u8 preem); | ||
45 | }; | ||
46 | |||
47 | struct nouveau_encoder { | 39 | struct nouveau_encoder { |
48 | struct drm_encoder_slave base; | 40 | struct drm_encoder_slave base; |
49 | 41 | ||
50 | struct dcb_output *dcb; | 42 | struct dcb_output *dcb; |
51 | int or; | 43 | int or; |
44 | struct nouveau_i2c_port *i2c; | ||
52 | 45 | ||
53 | /* different to drm_encoder.crtc, this reflects what's | 46 | /* different to drm_encoder.crtc, this reflects what's |
54 | * actually programmed on the hw, not the proposed crtc */ | 47 | * actually programmed on the hw, not the proposed crtc */ |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 1d049be79f74..6c946837a0aa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c | |||
@@ -33,14 +33,14 @@ | |||
33 | #include "nouveau_dma.h" | 33 | #include "nouveau_dma.h" |
34 | #include "nouveau_fence.h" | 34 | #include "nouveau_fence.h" |
35 | 35 | ||
36 | #include <engine/fifo.h> | ||
37 | |||
36 | void | 38 | void |
37 | nouveau_fence_context_del(struct nouveau_fence_chan *fctx) | 39 | nouveau_fence_context_del(struct nouveau_fence_chan *fctx) |
38 | { | 40 | { |
39 | struct nouveau_fence *fence, *fnext; | 41 | struct nouveau_fence *fence, *fnext; |
40 | spin_lock(&fctx->lock); | 42 | spin_lock(&fctx->lock); |
41 | list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { | 43 | list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { |
42 | if (fence->work) | ||
43 | fence->work(fence->priv, false); | ||
44 | fence->channel = NULL; | 44 | fence->channel = NULL; |
45 | list_del(&fence->head); | 45 | list_del(&fence->head); |
46 | nouveau_fence_unref(&fence); | 46 | nouveau_fence_unref(&fence); |
@@ -59,17 +59,14 @@ nouveau_fence_context_new(struct nouveau_fence_chan *fctx) | |||
59 | static void | 59 | static void |
60 | nouveau_fence_update(struct nouveau_channel *chan) | 60 | nouveau_fence_update(struct nouveau_channel *chan) |
61 | { | 61 | { |
62 | struct nouveau_fence_priv *priv = chan->drm->fence; | ||
63 | struct nouveau_fence_chan *fctx = chan->fence; | 62 | struct nouveau_fence_chan *fctx = chan->fence; |
64 | struct nouveau_fence *fence, *fnext; | 63 | struct nouveau_fence *fence, *fnext; |
65 | 64 | ||
66 | spin_lock(&fctx->lock); | 65 | spin_lock(&fctx->lock); |
67 | list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { | 66 | list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { |
68 | if (priv->read(chan) < fence->sequence) | 67 | if (fctx->read(chan) < fence->sequence) |
69 | break; | 68 | break; |
70 | 69 | ||
71 | if (fence->work) | ||
72 | fence->work(fence->priv, true); | ||
73 | fence->channel = NULL; | 70 | fence->channel = NULL; |
74 | list_del(&fence->head); | 71 | list_del(&fence->head); |
75 | nouveau_fence_unref(&fence); | 72 | nouveau_fence_unref(&fence); |
@@ -80,7 +77,6 @@ nouveau_fence_update(struct nouveau_channel *chan) | |||
80 | int | 77 | int |
81 | nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) | 78 | nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) |
82 | { | 79 | { |
83 | struct nouveau_fence_priv *priv = chan->drm->fence; | ||
84 | struct nouveau_fence_chan *fctx = chan->fence; | 80 | struct nouveau_fence_chan *fctx = chan->fence; |
85 | int ret; | 81 | int ret; |
86 | 82 | ||
@@ -88,7 +84,7 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) | |||
88 | fence->timeout = jiffies + (3 * DRM_HZ); | 84 | fence->timeout = jiffies + (3 * DRM_HZ); |
89 | fence->sequence = ++fctx->sequence; | 85 | fence->sequence = ++fctx->sequence; |
90 | 86 | ||
91 | ret = priv->emit(fence); | 87 | ret = fctx->emit(fence); |
92 | if (!ret) { | 88 | if (!ret) { |
93 | kref_get(&fence->kref); | 89 | kref_get(&fence->kref); |
94 | spin_lock(&fctx->lock); | 90 | spin_lock(&fctx->lock); |
@@ -107,13 +103,87 @@ nouveau_fence_done(struct nouveau_fence *fence) | |||
107 | return !fence->channel; | 103 | return !fence->channel; |
108 | } | 104 | } |
109 | 105 | ||
106 | struct nouveau_fence_uevent { | ||
107 | struct nouveau_eventh handler; | ||
108 | struct nouveau_fence_priv *priv; | ||
109 | }; | ||
110 | |||
111 | static int | ||
112 | nouveau_fence_wait_uevent_handler(struct nouveau_eventh *event, int index) | ||
113 | { | ||
114 | struct nouveau_fence_uevent *uevent = | ||
115 | container_of(event, struct nouveau_fence_uevent, handler); | ||
116 | wake_up_all(&uevent->priv->waiting); | ||
117 | return NVKM_EVENT_KEEP; | ||
118 | } | ||
119 | |||
120 | static int | ||
121 | nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) | ||
122 | |||
123 | { | ||
124 | struct nouveau_channel *chan = fence->channel; | ||
125 | struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device); | ||
126 | struct nouveau_fence_priv *priv = chan->drm->fence; | ||
127 | struct nouveau_fence_uevent uevent = { | ||
128 | .handler.func = nouveau_fence_wait_uevent_handler, | ||
129 | .priv = priv, | ||
130 | }; | ||
131 | int ret = 0; | ||
132 | |||
133 | nouveau_event_get(pfifo->uevent, 0, &uevent.handler); | ||
134 | |||
135 | if (fence->timeout) { | ||
136 | unsigned long timeout = fence->timeout - jiffies; | ||
137 | |||
138 | if (time_before(jiffies, fence->timeout)) { | ||
139 | if (intr) { | ||
140 | ret = wait_event_interruptible_timeout( | ||
141 | priv->waiting, | ||
142 | nouveau_fence_done(fence), | ||
143 | timeout); | ||
144 | } else { | ||
145 | ret = wait_event_timeout(priv->waiting, | ||
146 | nouveau_fence_done(fence), | ||
147 | timeout); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | if (ret >= 0) { | ||
152 | fence->timeout = jiffies + ret; | ||
153 | if (time_after_eq(jiffies, fence->timeout)) | ||
154 | ret = -EBUSY; | ||
155 | } | ||
156 | } else { | ||
157 | if (intr) { | ||
158 | ret = wait_event_interruptible(priv->waiting, | ||
159 | nouveau_fence_done(fence)); | ||
160 | } else { | ||
161 | wait_event(priv->waiting, nouveau_fence_done(fence)); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | nouveau_event_put(pfifo->uevent, 0, &uevent.handler); | ||
166 | if (unlikely(ret < 0)) | ||
167 | return ret; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
110 | int | 172 | int |
111 | nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) | 173 | nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) |
112 | { | 174 | { |
175 | struct nouveau_channel *chan = fence->channel; | ||
176 | struct nouveau_fence_priv *priv = chan ? chan->drm->fence : NULL; | ||
113 | unsigned long sleep_time = NSEC_PER_MSEC / 1000; | 177 | unsigned long sleep_time = NSEC_PER_MSEC / 1000; |
114 | ktime_t t; | 178 | ktime_t t; |
115 | int ret = 0; | 179 | int ret = 0; |
116 | 180 | ||
181 | while (priv && priv->uevent && lazy && !nouveau_fence_done(fence)) { | ||
182 | ret = nouveau_fence_wait_uevent(fence, intr); | ||
183 | if (ret < 0) | ||
184 | return ret; | ||
185 | } | ||
186 | |||
117 | while (!nouveau_fence_done(fence)) { | 187 | while (!nouveau_fence_done(fence)) { |
118 | if (fence->timeout && time_after_eq(jiffies, fence->timeout)) { | 188 | if (fence->timeout && time_after_eq(jiffies, fence->timeout)) { |
119 | ret = -EBUSY; | 189 | ret = -EBUSY; |
@@ -143,14 +213,14 @@ nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) | |||
143 | int | 213 | int |
144 | nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) | 214 | nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) |
145 | { | 215 | { |
146 | struct nouveau_fence_priv *priv = chan->drm->fence; | 216 | struct nouveau_fence_chan *fctx = chan->fence; |
147 | struct nouveau_channel *prev; | 217 | struct nouveau_channel *prev; |
148 | int ret = 0; | 218 | int ret = 0; |
149 | 219 | ||
150 | prev = fence ? fence->channel : NULL; | 220 | prev = fence ? fence->channel : NULL; |
151 | if (prev) { | 221 | if (prev) { |
152 | if (unlikely(prev != chan && !nouveau_fence_done(fence))) { | 222 | if (unlikely(prev != chan && !nouveau_fence_done(fence))) { |
153 | ret = priv->sync(fence, prev, chan); | 223 | ret = fctx->sync(fence, prev, chan); |
154 | if (unlikely(ret)) | 224 | if (unlikely(ret)) |
155 | ret = nouveau_fence_wait(fence, true, false); | 225 | ret = nouveau_fence_wait(fence, true, false); |
156 | } | 226 | } |
@@ -182,7 +252,8 @@ nouveau_fence_ref(struct nouveau_fence *fence) | |||
182 | } | 252 | } |
183 | 253 | ||
184 | int | 254 | int |
185 | nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence) | 255 | nouveau_fence_new(struct nouveau_channel *chan, bool sysmem, |
256 | struct nouveau_fence **pfence) | ||
186 | { | 257 | { |
187 | struct nouveau_fence *fence; | 258 | struct nouveau_fence *fence; |
188 | int ret = 0; | 259 | int ret = 0; |
@@ -193,13 +264,13 @@ nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence) | |||
193 | fence = kzalloc(sizeof(*fence), GFP_KERNEL); | 264 | fence = kzalloc(sizeof(*fence), GFP_KERNEL); |
194 | if (!fence) | 265 | if (!fence) |
195 | return -ENOMEM; | 266 | return -ENOMEM; |
267 | |||
268 | fence->sysmem = sysmem; | ||
196 | kref_init(&fence->kref); | 269 | kref_init(&fence->kref); |
197 | 270 | ||
198 | if (chan) { | 271 | ret = nouveau_fence_emit(fence, chan); |
199 | ret = nouveau_fence_emit(fence, chan); | 272 | if (ret) |
200 | if (ret) | 273 | nouveau_fence_unref(&fence); |
201 | nouveau_fence_unref(&fence); | ||
202 | } | ||
203 | 274 | ||
204 | *pfence = fence; | 275 | *pfence = fence; |
205 | return ret; | 276 | return ret; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index cdb83acdffe2..c89943407b52 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h | |||
@@ -7,15 +7,15 @@ struct nouveau_fence { | |||
7 | struct list_head head; | 7 | struct list_head head; |
8 | struct kref kref; | 8 | struct kref kref; |
9 | 9 | ||
10 | bool sysmem; | ||
11 | |||
10 | struct nouveau_channel *channel; | 12 | struct nouveau_channel *channel; |
11 | unsigned long timeout; | 13 | unsigned long timeout; |
12 | u32 sequence; | 14 | u32 sequence; |
13 | |||
14 | void (*work)(void *priv, bool signalled); | ||
15 | void *priv; | ||
16 | }; | 15 | }; |
17 | 16 | ||
18 | int nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **); | 17 | int nouveau_fence_new(struct nouveau_channel *, bool sysmem, |
18 | struct nouveau_fence **); | ||
19 | struct nouveau_fence * | 19 | struct nouveau_fence * |
20 | nouveau_fence_ref(struct nouveau_fence *); | 20 | nouveau_fence_ref(struct nouveau_fence *); |
21 | void nouveau_fence_unref(struct nouveau_fence **); | 21 | void nouveau_fence_unref(struct nouveau_fence **); |
@@ -29,6 +29,13 @@ struct nouveau_fence_chan { | |||
29 | struct list_head pending; | 29 | struct list_head pending; |
30 | struct list_head flip; | 30 | struct list_head flip; |
31 | 31 | ||
32 | int (*emit)(struct nouveau_fence *); | ||
33 | int (*sync)(struct nouveau_fence *, struct nouveau_channel *, | ||
34 | struct nouveau_channel *); | ||
35 | u32 (*read)(struct nouveau_channel *); | ||
36 | int (*emit32)(struct nouveau_channel *, u64, u32); | ||
37 | int (*sync32)(struct nouveau_channel *, u64, u32); | ||
38 | |||
32 | spinlock_t lock; | 39 | spinlock_t lock; |
33 | u32 sequence; | 40 | u32 sequence; |
34 | }; | 41 | }; |
@@ -39,10 +46,9 @@ struct nouveau_fence_priv { | |||
39 | void (*resume)(struct nouveau_drm *); | 46 | void (*resume)(struct nouveau_drm *); |
40 | int (*context_new)(struct nouveau_channel *); | 47 | int (*context_new)(struct nouveau_channel *); |
41 | void (*context_del)(struct nouveau_channel *); | 48 | void (*context_del)(struct nouveau_channel *); |
42 | int (*emit)(struct nouveau_fence *); | 49 | |
43 | int (*sync)(struct nouveau_fence *, struct nouveau_channel *, | 50 | wait_queue_head_t waiting; |
44 | struct nouveau_channel *); | 51 | bool uevent; |
45 | u32 (*read)(struct nouveau_channel *); | ||
46 | }; | 52 | }; |
47 | 53 | ||
48 | #define nouveau_fence(drm) ((struct nouveau_fence_priv *)(drm)->fence) | 54 | #define nouveau_fence(drm) ((struct nouveau_fence_priv *)(drm)->fence) |
@@ -60,13 +66,31 @@ u32 nv10_fence_read(struct nouveau_channel *); | |||
60 | void nv10_fence_context_del(struct nouveau_channel *); | 66 | void nv10_fence_context_del(struct nouveau_channel *); |
61 | void nv10_fence_destroy(struct nouveau_drm *); | 67 | void nv10_fence_destroy(struct nouveau_drm *); |
62 | int nv10_fence_create(struct nouveau_drm *); | 68 | int nv10_fence_create(struct nouveau_drm *); |
69 | |||
70 | int nv17_fence_create(struct nouveau_drm *); | ||
63 | void nv17_fence_resume(struct nouveau_drm *drm); | 71 | void nv17_fence_resume(struct nouveau_drm *drm); |
64 | 72 | ||
65 | int nv50_fence_create(struct nouveau_drm *); | 73 | int nv50_fence_create(struct nouveau_drm *); |
66 | int nv84_fence_create(struct nouveau_drm *); | 74 | int nv84_fence_create(struct nouveau_drm *); |
67 | int nvc0_fence_create(struct nouveau_drm *); | 75 | int nvc0_fence_create(struct nouveau_drm *); |
68 | u64 nvc0_fence_crtc(struct nouveau_channel *, int crtc); | ||
69 | 76 | ||
70 | int nouveau_flip_complete(void *chan); | 77 | int nouveau_flip_complete(void *chan); |
71 | 78 | ||
79 | struct nv84_fence_chan { | ||
80 | struct nouveau_fence_chan base; | ||
81 | struct nouveau_vma vma; | ||
82 | struct nouveau_vma vma_gart; | ||
83 | struct nouveau_vma dispc_vma[4]; | ||
84 | }; | ||
85 | |||
86 | struct nv84_fence_priv { | ||
87 | struct nouveau_fence_priv base; | ||
88 | struct nouveau_bo *bo; | ||
89 | struct nouveau_bo *bo_gart; | ||
90 | u32 *suspend; | ||
91 | }; | ||
92 | |||
93 | u64 nv84_fence_crtc(struct nouveau_channel *, int); | ||
94 | int nv84_fence_context_new(struct nouveau_channel *); | ||
95 | |||
72 | #endif | 96 | #endif |
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index d98bee012cab..b4b4d0c1f4af 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c | |||
@@ -203,6 +203,7 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, | |||
203 | struct drm_file *file_priv) | 203 | struct drm_file *file_priv) |
204 | { | 204 | { |
205 | struct nouveau_drm *drm = nouveau_drm(dev); | 205 | struct nouveau_drm *drm = nouveau_drm(dev); |
206 | struct nouveau_cli *cli = nouveau_cli(file_priv); | ||
206 | struct nouveau_fb *pfb = nouveau_fb(drm->device); | 207 | struct nouveau_fb *pfb = nouveau_fb(drm->device); |
207 | struct drm_nouveau_gem_new *req = data; | 208 | struct drm_nouveau_gem_new *req = data; |
208 | struct nouveau_bo *nvbo = NULL; | 209 | struct nouveau_bo *nvbo = NULL; |
@@ -211,7 +212,7 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, | |||
211 | drm->ttm.bdev.dev_mapping = drm->dev->dev_mapping; | 212 | drm->ttm.bdev.dev_mapping = drm->dev->dev_mapping; |
212 | 213 | ||
213 | if (!pfb->memtype_valid(pfb, req->info.tile_flags)) { | 214 | if (!pfb->memtype_valid(pfb, req->info.tile_flags)) { |
214 | NV_ERROR(drm, "bad page flags: 0x%08x\n", req->info.tile_flags); | 215 | NV_ERROR(cli, "bad page flags: 0x%08x\n", req->info.tile_flags); |
215 | return -EINVAL; | 216 | return -EINVAL; |
216 | } | 217 | } |
217 | 218 | ||
@@ -313,6 +314,7 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv, | |||
313 | struct drm_nouveau_gem_pushbuf_bo *pbbo, | 314 | struct drm_nouveau_gem_pushbuf_bo *pbbo, |
314 | int nr_buffers, struct validate_op *op) | 315 | int nr_buffers, struct validate_op *op) |
315 | { | 316 | { |
317 | struct nouveau_cli *cli = nouveau_cli(file_priv); | ||
316 | struct drm_device *dev = chan->drm->dev; | 318 | struct drm_device *dev = chan->drm->dev; |
317 | struct nouveau_drm *drm = nouveau_drm(dev); | 319 | struct nouveau_drm *drm = nouveau_drm(dev); |
318 | uint32_t sequence; | 320 | uint32_t sequence; |
@@ -323,7 +325,7 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv, | |||
323 | sequence = atomic_add_return(1, &drm->ttm.validate_sequence); | 325 | sequence = atomic_add_return(1, &drm->ttm.validate_sequence); |
324 | retry: | 326 | retry: |
325 | if (++trycnt > 100000) { | 327 | if (++trycnt > 100000) { |
326 | NV_ERROR(drm, "%s failed and gave up.\n", __func__); | 328 | NV_ERROR(cli, "%s failed and gave up.\n", __func__); |
327 | return -EINVAL; | 329 | return -EINVAL; |
328 | } | 330 | } |
329 | 331 | ||
@@ -334,7 +336,7 @@ retry: | |||
334 | 336 | ||
335 | gem = drm_gem_object_lookup(dev, file_priv, b->handle); | 337 | gem = drm_gem_object_lookup(dev, file_priv, b->handle); |
336 | if (!gem) { | 338 | if (!gem) { |
337 | NV_ERROR(drm, "Unknown handle 0x%08x\n", b->handle); | 339 | NV_ERROR(cli, "Unknown handle 0x%08x\n", b->handle); |
338 | validate_fini(op, NULL); | 340 | validate_fini(op, NULL); |
339 | return -ENOENT; | 341 | return -ENOENT; |
340 | } | 342 | } |
@@ -346,7 +348,7 @@ retry: | |||
346 | } | 348 | } |
347 | 349 | ||
348 | if (nvbo->reserved_by && nvbo->reserved_by == file_priv) { | 350 | if (nvbo->reserved_by && nvbo->reserved_by == file_priv) { |
349 | NV_ERROR(drm, "multiple instances of buffer %d on " | 351 | NV_ERROR(cli, "multiple instances of buffer %d on " |
350 | "validation list\n", b->handle); | 352 | "validation list\n", b->handle); |
351 | drm_gem_object_unreference_unlocked(gem); | 353 | drm_gem_object_unreference_unlocked(gem); |
352 | validate_fini(op, NULL); | 354 | validate_fini(op, NULL); |
@@ -366,7 +368,7 @@ retry: | |||
366 | if (unlikely(ret)) { | 368 | if (unlikely(ret)) { |
367 | drm_gem_object_unreference_unlocked(gem); | 369 | drm_gem_object_unreference_unlocked(gem); |
368 | if (ret != -ERESTARTSYS) | 370 | if (ret != -ERESTARTSYS) |
369 | NV_ERROR(drm, "fail reserve\n"); | 371 | NV_ERROR(cli, "fail reserve\n"); |
370 | return ret; | 372 | return ret; |
371 | } | 373 | } |
372 | } | 374 | } |
@@ -384,7 +386,7 @@ retry: | |||
384 | if (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART) | 386 | if (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART) |
385 | list_add_tail(&nvbo->entry, &op->gart_list); | 387 | list_add_tail(&nvbo->entry, &op->gart_list); |
386 | else { | 388 | else { |
387 | NV_ERROR(drm, "invalid valid domains: 0x%08x\n", | 389 | NV_ERROR(cli, "invalid valid domains: 0x%08x\n", |
388 | b->valid_domains); | 390 | b->valid_domains); |
389 | list_add_tail(&nvbo->entry, &op->both_list); | 391 | list_add_tail(&nvbo->entry, &op->both_list); |
390 | validate_fini(op, NULL); | 392 | validate_fini(op, NULL); |
@@ -417,8 +419,9 @@ validate_sync(struct nouveau_channel *chan, struct nouveau_bo *nvbo) | |||
417 | } | 419 | } |
418 | 420 | ||
419 | static int | 421 | static int |
420 | validate_list(struct nouveau_channel *chan, struct list_head *list, | 422 | validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, |
421 | struct drm_nouveau_gem_pushbuf_bo *pbbo, uint64_t user_pbbo_ptr) | 423 | struct list_head *list, struct drm_nouveau_gem_pushbuf_bo *pbbo, |
424 | uint64_t user_pbbo_ptr) | ||
422 | { | 425 | { |
423 | struct nouveau_drm *drm = chan->drm; | 426 | struct nouveau_drm *drm = chan->drm; |
424 | struct drm_nouveau_gem_pushbuf_bo __user *upbbo = | 427 | struct drm_nouveau_gem_pushbuf_bo __user *upbbo = |
@@ -431,7 +434,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, | |||
431 | 434 | ||
432 | ret = validate_sync(chan, nvbo); | 435 | ret = validate_sync(chan, nvbo); |
433 | if (unlikely(ret)) { | 436 | if (unlikely(ret)) { |
434 | NV_ERROR(drm, "fail pre-validate sync\n"); | 437 | NV_ERROR(cli, "fail pre-validate sync\n"); |
435 | return ret; | 438 | return ret; |
436 | } | 439 | } |
437 | 440 | ||
@@ -439,20 +442,20 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, | |||
439 | b->write_domains, | 442 | b->write_domains, |
440 | b->valid_domains); | 443 | b->valid_domains); |
441 | if (unlikely(ret)) { | 444 | if (unlikely(ret)) { |
442 | NV_ERROR(drm, "fail set_domain\n"); | 445 | NV_ERROR(cli, "fail set_domain\n"); |
443 | return ret; | 446 | return ret; |
444 | } | 447 | } |
445 | 448 | ||
446 | ret = nouveau_bo_validate(nvbo, true, false); | 449 | ret = nouveau_bo_validate(nvbo, true, false); |
447 | if (unlikely(ret)) { | 450 | if (unlikely(ret)) { |
448 | if (ret != -ERESTARTSYS) | 451 | if (ret != -ERESTARTSYS) |
449 | NV_ERROR(drm, "fail ttm_validate\n"); | 452 | NV_ERROR(cli, "fail ttm_validate\n"); |
450 | return ret; | 453 | return ret; |
451 | } | 454 | } |
452 | 455 | ||
453 | ret = validate_sync(chan, nvbo); | 456 | ret = validate_sync(chan, nvbo); |
454 | if (unlikely(ret)) { | 457 | if (unlikely(ret)) { |
455 | NV_ERROR(drm, "fail post-validate sync\n"); | 458 | NV_ERROR(cli, "fail post-validate sync\n"); |
456 | return ret; | 459 | return ret; |
457 | } | 460 | } |
458 | 461 | ||
@@ -488,7 +491,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, | |||
488 | uint64_t user_buffers, int nr_buffers, | 491 | uint64_t user_buffers, int nr_buffers, |
489 | struct validate_op *op, int *apply_relocs) | 492 | struct validate_op *op, int *apply_relocs) |
490 | { | 493 | { |
491 | struct nouveau_drm *drm = chan->drm; | 494 | struct nouveau_cli *cli = nouveau_cli(file_priv); |
492 | int ret, relocs = 0; | 495 | int ret, relocs = 0; |
493 | 496 | ||
494 | INIT_LIST_HEAD(&op->vram_list); | 497 | INIT_LIST_HEAD(&op->vram_list); |
@@ -501,32 +504,32 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, | |||
501 | ret = validate_init(chan, file_priv, pbbo, nr_buffers, op); | 504 | ret = validate_init(chan, file_priv, pbbo, nr_buffers, op); |
502 | if (unlikely(ret)) { | 505 | if (unlikely(ret)) { |
503 | if (ret != -ERESTARTSYS) | 506 | if (ret != -ERESTARTSYS) |
504 | NV_ERROR(drm, "validate_init\n"); | 507 | NV_ERROR(cli, "validate_init\n"); |
505 | return ret; | 508 | return ret; |
506 | } | 509 | } |
507 | 510 | ||
508 | ret = validate_list(chan, &op->vram_list, pbbo, user_buffers); | 511 | ret = validate_list(chan, cli, &op->vram_list, pbbo, user_buffers); |
509 | if (unlikely(ret < 0)) { | 512 | if (unlikely(ret < 0)) { |
510 | if (ret != -ERESTARTSYS) | 513 | if (ret != -ERESTARTSYS) |
511 | NV_ERROR(drm, "validate vram_list\n"); | 514 | NV_ERROR(cli, "validate vram_list\n"); |
512 | validate_fini(op, NULL); | 515 | validate_fini(op, NULL); |
513 | return ret; | 516 | return ret; |
514 | } | 517 | } |
515 | relocs += ret; | 518 | relocs += ret; |
516 | 519 | ||
517 | ret = validate_list(chan, &op->gart_list, pbbo, user_buffers); | 520 | ret = validate_list(chan, cli, &op->gart_list, pbbo, user_buffers); |
518 | if (unlikely(ret < 0)) { | 521 | if (unlikely(ret < 0)) { |
519 | if (ret != -ERESTARTSYS) | 522 | if (ret != -ERESTARTSYS) |
520 | NV_ERROR(drm, "validate gart_list\n"); | 523 | NV_ERROR(cli, "validate gart_list\n"); |
521 | validate_fini(op, NULL); | 524 | validate_fini(op, NULL); |
522 | return ret; | 525 | return ret; |
523 | } | 526 | } |
524 | relocs += ret; | 527 | relocs += ret; |
525 | 528 | ||
526 | ret = validate_list(chan, &op->both_list, pbbo, user_buffers); | 529 | ret = validate_list(chan, cli, &op->both_list, pbbo, user_buffers); |
527 | if (unlikely(ret < 0)) { | 530 | if (unlikely(ret < 0)) { |
528 | if (ret != -ERESTARTSYS) | 531 | if (ret != -ERESTARTSYS) |
529 | NV_ERROR(drm, "validate both_list\n"); | 532 | NV_ERROR(cli, "validate both_list\n"); |
530 | validate_fini(op, NULL); | 533 | validate_fini(op, NULL); |
531 | return ret; | 534 | return ret; |
532 | } | 535 | } |
@@ -555,11 +558,10 @@ u_memcpya(uint64_t user, unsigned nmemb, unsigned size) | |||
555 | } | 558 | } |
556 | 559 | ||
557 | static int | 560 | static int |
558 | nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev, | 561 | nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, |
559 | struct drm_nouveau_gem_pushbuf *req, | 562 | struct drm_nouveau_gem_pushbuf *req, |
560 | struct drm_nouveau_gem_pushbuf_bo *bo) | 563 | struct drm_nouveau_gem_pushbuf_bo *bo) |
561 | { | 564 | { |
562 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
563 | struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL; | 565 | struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL; |
564 | int ret = 0; | 566 | int ret = 0; |
565 | unsigned i; | 567 | unsigned i; |
@@ -575,7 +577,7 @@ nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev, | |||
575 | uint32_t data; | 577 | uint32_t data; |
576 | 578 | ||
577 | if (unlikely(r->bo_index > req->nr_buffers)) { | 579 | if (unlikely(r->bo_index > req->nr_buffers)) { |
578 | NV_ERROR(drm, "reloc bo index invalid\n"); | 580 | NV_ERROR(cli, "reloc bo index invalid\n"); |
579 | ret = -EINVAL; | 581 | ret = -EINVAL; |
580 | break; | 582 | break; |
581 | } | 583 | } |
@@ -585,7 +587,7 @@ nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev, | |||
585 | continue; | 587 | continue; |
586 | 588 | ||
587 | if (unlikely(r->reloc_bo_index > req->nr_buffers)) { | 589 | if (unlikely(r->reloc_bo_index > req->nr_buffers)) { |
588 | NV_ERROR(drm, "reloc container bo index invalid\n"); | 590 | NV_ERROR(cli, "reloc container bo index invalid\n"); |
589 | ret = -EINVAL; | 591 | ret = -EINVAL; |
590 | break; | 592 | break; |
591 | } | 593 | } |
@@ -593,7 +595,7 @@ nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev, | |||
593 | 595 | ||
594 | if (unlikely(r->reloc_bo_offset + 4 > | 596 | if (unlikely(r->reloc_bo_offset + 4 > |
595 | nvbo->bo.mem.num_pages << PAGE_SHIFT)) { | 597 | nvbo->bo.mem.num_pages << PAGE_SHIFT)) { |
596 | NV_ERROR(drm, "reloc outside of bo\n"); | 598 | NV_ERROR(cli, "reloc outside of bo\n"); |
597 | ret = -EINVAL; | 599 | ret = -EINVAL; |
598 | break; | 600 | break; |
599 | } | 601 | } |
@@ -602,7 +604,7 @@ nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev, | |||
602 | ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, | 604 | ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, |
603 | &nvbo->kmap); | 605 | &nvbo->kmap); |
604 | if (ret) { | 606 | if (ret) { |
605 | NV_ERROR(drm, "failed kmap for reloc\n"); | 607 | NV_ERROR(cli, "failed kmap for reloc\n"); |
606 | break; | 608 | break; |
607 | } | 609 | } |
608 | nvbo->validate_mapped = true; | 610 | nvbo->validate_mapped = true; |
@@ -627,7 +629,7 @@ nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev, | |||
627 | ret = ttm_bo_wait(&nvbo->bo, false, false, false); | 629 | ret = ttm_bo_wait(&nvbo->bo, false, false, false); |
628 | spin_unlock(&nvbo->bo.bdev->fence_lock); | 630 | spin_unlock(&nvbo->bo.bdev->fence_lock); |
629 | if (ret) { | 631 | if (ret) { |
630 | NV_ERROR(drm, "reloc wait_idle failed: %d\n", ret); | 632 | NV_ERROR(cli, "reloc wait_idle failed: %d\n", ret); |
631 | break; | 633 | break; |
632 | } | 634 | } |
633 | 635 | ||
@@ -643,6 +645,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
643 | struct drm_file *file_priv) | 645 | struct drm_file *file_priv) |
644 | { | 646 | { |
645 | struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); | 647 | struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); |
648 | struct nouveau_cli *cli = nouveau_cli(file_priv); | ||
646 | struct nouveau_abi16_chan *temp; | 649 | struct nouveau_abi16_chan *temp; |
647 | struct nouveau_drm *drm = nouveau_drm(dev); | 650 | struct nouveau_drm *drm = nouveau_drm(dev); |
648 | struct drm_nouveau_gem_pushbuf *req = data; | 651 | struct drm_nouveau_gem_pushbuf *req = data; |
@@ -672,19 +675,19 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
672 | goto out_next; | 675 | goto out_next; |
673 | 676 | ||
674 | if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) { | 677 | if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) { |
675 | NV_ERROR(drm, "pushbuf push count exceeds limit: %d max %d\n", | 678 | NV_ERROR(cli, "pushbuf push count exceeds limit: %d max %d\n", |
676 | req->nr_push, NOUVEAU_GEM_MAX_PUSH); | 679 | req->nr_push, NOUVEAU_GEM_MAX_PUSH); |
677 | return nouveau_abi16_put(abi16, -EINVAL); | 680 | return nouveau_abi16_put(abi16, -EINVAL); |
678 | } | 681 | } |
679 | 682 | ||
680 | if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) { | 683 | if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) { |
681 | NV_ERROR(drm, "pushbuf bo count exceeds limit: %d max %d\n", | 684 | NV_ERROR(cli, "pushbuf bo count exceeds limit: %d max %d\n", |
682 | req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS); | 685 | req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS); |
683 | return nouveau_abi16_put(abi16, -EINVAL); | 686 | return nouveau_abi16_put(abi16, -EINVAL); |
684 | } | 687 | } |
685 | 688 | ||
686 | if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) { | 689 | if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) { |
687 | NV_ERROR(drm, "pushbuf reloc count exceeds limit: %d max %d\n", | 690 | NV_ERROR(cli, "pushbuf reloc count exceeds limit: %d max %d\n", |
688 | req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS); | 691 | req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS); |
689 | return nouveau_abi16_put(abi16, -EINVAL); | 692 | return nouveau_abi16_put(abi16, -EINVAL); |
690 | } | 693 | } |
@@ -702,7 +705,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
702 | /* Ensure all push buffers are on validate list */ | 705 | /* Ensure all push buffers are on validate list */ |
703 | for (i = 0; i < req->nr_push; i++) { | 706 | for (i = 0; i < req->nr_push; i++) { |
704 | if (push[i].bo_index >= req->nr_buffers) { | 707 | if (push[i].bo_index >= req->nr_buffers) { |
705 | NV_ERROR(drm, "push %d buffer not in list\n", i); | 708 | NV_ERROR(cli, "push %d buffer not in list\n", i); |
706 | ret = -EINVAL; | 709 | ret = -EINVAL; |
707 | goto out_prevalid; | 710 | goto out_prevalid; |
708 | } | 711 | } |
@@ -713,15 +716,15 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
713 | req->nr_buffers, &op, &do_reloc); | 716 | req->nr_buffers, &op, &do_reloc); |
714 | if (ret) { | 717 | if (ret) { |
715 | if (ret != -ERESTARTSYS) | 718 | if (ret != -ERESTARTSYS) |
716 | NV_ERROR(drm, "validate: %d\n", ret); | 719 | NV_ERROR(cli, "validate: %d\n", ret); |
717 | goto out_prevalid; | 720 | goto out_prevalid; |
718 | } | 721 | } |
719 | 722 | ||
720 | /* Apply any relocations that are required */ | 723 | /* Apply any relocations that are required */ |
721 | if (do_reloc) { | 724 | if (do_reloc) { |
722 | ret = nouveau_gem_pushbuf_reloc_apply(dev, req, bo); | 725 | ret = nouveau_gem_pushbuf_reloc_apply(cli, req, bo); |
723 | if (ret) { | 726 | if (ret) { |
724 | NV_ERROR(drm, "reloc apply: %d\n", ret); | 727 | NV_ERROR(cli, "reloc apply: %d\n", ret); |
725 | goto out; | 728 | goto out; |
726 | } | 729 | } |
727 | } | 730 | } |
@@ -729,7 +732,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
729 | if (chan->dma.ib_max) { | 732 | if (chan->dma.ib_max) { |
730 | ret = nouveau_dma_wait(chan, req->nr_push + 1, 16); | 733 | ret = nouveau_dma_wait(chan, req->nr_push + 1, 16); |
731 | if (ret) { | 734 | if (ret) { |
732 | NV_ERROR(drm, "nv50cal_space: %d\n", ret); | 735 | NV_ERROR(cli, "nv50cal_space: %d\n", ret); |
733 | goto out; | 736 | goto out; |
734 | } | 737 | } |
735 | 738 | ||
@@ -744,7 +747,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
744 | if (nv_device(drm->device)->chipset >= 0x25) { | 747 | if (nv_device(drm->device)->chipset >= 0x25) { |
745 | ret = RING_SPACE(chan, req->nr_push * 2); | 748 | ret = RING_SPACE(chan, req->nr_push * 2); |
746 | if (ret) { | 749 | if (ret) { |
747 | NV_ERROR(drm, "cal_space: %d\n", ret); | 750 | NV_ERROR(cli, "cal_space: %d\n", ret); |
748 | goto out; | 751 | goto out; |
749 | } | 752 | } |
750 | 753 | ||
@@ -758,7 +761,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
758 | } else { | 761 | } else { |
759 | ret = RING_SPACE(chan, req->nr_push * (2 + NOUVEAU_DMA_SKIPS)); | 762 | ret = RING_SPACE(chan, req->nr_push * (2 + NOUVEAU_DMA_SKIPS)); |
760 | if (ret) { | 763 | if (ret) { |
761 | NV_ERROR(drm, "jmp_space: %d\n", ret); | 764 | NV_ERROR(cli, "jmp_space: %d\n", ret); |
762 | goto out; | 765 | goto out; |
763 | } | 766 | } |
764 | 767 | ||
@@ -794,9 +797,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
794 | } | 797 | } |
795 | } | 798 | } |
796 | 799 | ||
797 | ret = nouveau_fence_new(chan, &fence); | 800 | ret = nouveau_fence_new(chan, false, &fence); |
798 | if (ret) { | 801 | if (ret) { |
799 | NV_ERROR(drm, "error fencing pushbuf: %d\n", ret); | 802 | NV_ERROR(cli, "error fencing pushbuf: %d\n", ret); |
800 | WIND_RING(chan); | 803 | WIND_RING(chan); |
801 | goto out; | 804 | goto out; |
802 | } | 805 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index a701ff5ffa5b..bb54098c6d97 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c | |||
@@ -409,6 +409,81 @@ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, | |||
409 | NULL, 0); | 409 | NULL, 0); |
410 | 410 | ||
411 | static ssize_t | 411 | static ssize_t |
412 | nouveau_hwmon_show_temp1_auto_point1_pwm(struct device *d, | ||
413 | struct device_attribute *a, char *buf) | ||
414 | { | ||
415 | return snprintf(buf, PAGE_SIZE, "%d\n", 100); | ||
416 | } | ||
417 | static SENSOR_DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO, | ||
418 | nouveau_hwmon_show_temp1_auto_point1_pwm, NULL, 0); | ||
419 | |||
420 | static ssize_t | ||
421 | nouveau_hwmon_temp1_auto_point1_temp(struct device *d, | ||
422 | struct device_attribute *a, char *buf) | ||
423 | { | ||
424 | struct drm_device *dev = dev_get_drvdata(d); | ||
425 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
426 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
427 | |||
428 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
429 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST) * 1000); | ||
430 | } | ||
431 | static ssize_t | ||
432 | nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d, | ||
433 | struct device_attribute *a, | ||
434 | const char *buf, size_t count) | ||
435 | { | ||
436 | struct drm_device *dev = dev_get_drvdata(d); | ||
437 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
438 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
439 | long value; | ||
440 | |||
441 | if (kstrtol(buf, 10, &value) == -EINVAL) | ||
442 | return count; | ||
443 | |||
444 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST, | ||
445 | value / 1000); | ||
446 | |||
447 | return count; | ||
448 | } | ||
449 | static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IRUGO | S_IWUSR, | ||
450 | nouveau_hwmon_temp1_auto_point1_temp, | ||
451 | nouveau_hwmon_set_temp1_auto_point1_temp, 0); | ||
452 | |||
453 | static ssize_t | ||
454 | nouveau_hwmon_temp1_auto_point1_temp_hyst(struct device *d, | ||
455 | struct device_attribute *a, char *buf) | ||
456 | { | ||
457 | struct drm_device *dev = dev_get_drvdata(d); | ||
458 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
459 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
460 | |||
461 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
462 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000); | ||
463 | } | ||
464 | static ssize_t | ||
465 | nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d, | ||
466 | struct device_attribute *a, | ||
467 | const char *buf, size_t count) | ||
468 | { | ||
469 | struct drm_device *dev = dev_get_drvdata(d); | ||
470 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
471 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
472 | long value; | ||
473 | |||
474 | if (kstrtol(buf, 10, &value) == -EINVAL) | ||
475 | return count; | ||
476 | |||
477 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST, | ||
478 | value / 1000); | ||
479 | |||
480 | return count; | ||
481 | } | ||
482 | static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, | ||
483 | nouveau_hwmon_temp1_auto_point1_temp_hyst, | ||
484 | nouveau_hwmon_set_temp1_auto_point1_temp_hyst, 0); | ||
485 | |||
486 | static ssize_t | ||
412 | nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) | 487 | nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) |
413 | { | 488 | { |
414 | struct drm_device *dev = dev_get_drvdata(d); | 489 | struct drm_device *dev = dev_get_drvdata(d); |
@@ -439,6 +514,38 @@ static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp, | |||
439 | 0); | 514 | 0); |
440 | 515 | ||
441 | static ssize_t | 516 | static ssize_t |
517 | nouveau_hwmon_max_temp_hyst(struct device *d, struct device_attribute *a, | ||
518 | char *buf) | ||
519 | { | ||
520 | struct drm_device *dev = dev_get_drvdata(d); | ||
521 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
522 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
523 | |||
524 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
525 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000); | ||
526 | } | ||
527 | static ssize_t | ||
528 | nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a, | ||
529 | const char *buf, size_t count) | ||
530 | { | ||
531 | struct drm_device *dev = dev_get_drvdata(d); | ||
532 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
533 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
534 | long value; | ||
535 | |||
536 | if (kstrtol(buf, 10, &value) == -EINVAL) | ||
537 | return count; | ||
538 | |||
539 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST, | ||
540 | value / 1000); | ||
541 | |||
542 | return count; | ||
543 | } | ||
544 | static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, | ||
545 | nouveau_hwmon_max_temp_hyst, | ||
546 | nouveau_hwmon_set_max_temp_hyst, 0); | ||
547 | |||
548 | static ssize_t | ||
442 | nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, | 549 | nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, |
443 | char *buf) | 550 | char *buf) |
444 | { | 551 | { |
@@ -471,6 +578,107 @@ static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, | |||
471 | nouveau_hwmon_set_critical_temp, | 578 | nouveau_hwmon_set_critical_temp, |
472 | 0); | 579 | 0); |
473 | 580 | ||
581 | static ssize_t | ||
582 | nouveau_hwmon_critical_temp_hyst(struct device *d, struct device_attribute *a, | ||
583 | char *buf) | ||
584 | { | ||
585 | struct drm_device *dev = dev_get_drvdata(d); | ||
586 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
587 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
588 | |||
589 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
590 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST) * 1000); | ||
591 | } | ||
592 | static ssize_t | ||
593 | nouveau_hwmon_set_critical_temp_hyst(struct device *d, | ||
594 | struct device_attribute *a, | ||
595 | const char *buf, | ||
596 | size_t count) | ||
597 | { | ||
598 | struct drm_device *dev = dev_get_drvdata(d); | ||
599 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
600 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
601 | long value; | ||
602 | |||
603 | if (kstrtol(buf, 10, &value) == -EINVAL) | ||
604 | return count; | ||
605 | |||
606 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST, | ||
607 | value / 1000); | ||
608 | |||
609 | return count; | ||
610 | } | ||
611 | static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR, | ||
612 | nouveau_hwmon_critical_temp_hyst, | ||
613 | nouveau_hwmon_set_critical_temp_hyst, 0); | ||
614 | static ssize_t | ||
615 | nouveau_hwmon_emergency_temp(struct device *d, struct device_attribute *a, | ||
616 | char *buf) | ||
617 | { | ||
618 | struct drm_device *dev = dev_get_drvdata(d); | ||
619 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
620 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
621 | |||
622 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
623 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN) * 1000); | ||
624 | } | ||
625 | static ssize_t | ||
626 | nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a, | ||
627 | const char *buf, | ||
628 | size_t count) | ||
629 | { | ||
630 | struct drm_device *dev = dev_get_drvdata(d); | ||
631 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
632 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
633 | long value; | ||
634 | |||
635 | if (kstrtol(buf, 10, &value) == -EINVAL) | ||
636 | return count; | ||
637 | |||
638 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN, value / 1000); | ||
639 | |||
640 | return count; | ||
641 | } | ||
642 | static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO | S_IWUSR, | ||
643 | nouveau_hwmon_emergency_temp, | ||
644 | nouveau_hwmon_set_emergency_temp, | ||
645 | 0); | ||
646 | |||
647 | static ssize_t | ||
648 | nouveau_hwmon_emergency_temp_hyst(struct device *d, struct device_attribute *a, | ||
649 | char *buf) | ||
650 | { | ||
651 | struct drm_device *dev = dev_get_drvdata(d); | ||
652 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
653 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
654 | |||
655 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
656 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000); | ||
657 | } | ||
658 | static ssize_t | ||
659 | nouveau_hwmon_set_emergency_temp_hyst(struct device *d, | ||
660 | struct device_attribute *a, | ||
661 | const char *buf, | ||
662 | size_t count) | ||
663 | { | ||
664 | struct drm_device *dev = dev_get_drvdata(d); | ||
665 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
666 | struct nouveau_therm *therm = nouveau_therm(drm->device); | ||
667 | long value; | ||
668 | |||
669 | if (kstrtol(buf, 10, &value) == -EINVAL) | ||
670 | return count; | ||
671 | |||
672 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST, | ||
673 | value / 1000); | ||
674 | |||
675 | return count; | ||
676 | } | ||
677 | static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO | S_IWUSR, | ||
678 | nouveau_hwmon_emergency_temp_hyst, | ||
679 | nouveau_hwmon_set_emergency_temp_hyst, | ||
680 | 0); | ||
681 | |||
474 | static ssize_t nouveau_hwmon_show_name(struct device *dev, | 682 | static ssize_t nouveau_hwmon_show_name(struct device *dev, |
475 | struct device_attribute *attr, | 683 | struct device_attribute *attr, |
476 | char *buf) | 684 | char *buf) |
@@ -490,7 +698,7 @@ static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO, | |||
490 | NULL, 0); | 698 | NULL, 0); |
491 | 699 | ||
492 | static ssize_t | 700 | static ssize_t |
493 | nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, | 701 | nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr, |
494 | char *buf) | 702 | char *buf) |
495 | { | 703 | { |
496 | struct drm_device *dev = dev_get_drvdata(d); | 704 | struct drm_device *dev = dev_get_drvdata(d); |
@@ -499,7 +707,7 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, | |||
499 | 707 | ||
500 | return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm)); | 708 | return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm)); |
501 | } | 709 | } |
502 | static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input, | 710 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, nouveau_hwmon_show_fan1_input, |
503 | NULL, 0); | 711 | NULL, 0); |
504 | 712 | ||
505 | static ssize_t | 713 | static ssize_t |
@@ -665,14 +873,21 @@ static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR, | |||
665 | 873 | ||
666 | static struct attribute *hwmon_attributes[] = { | 874 | static struct attribute *hwmon_attributes[] = { |
667 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 875 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
876 | &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr, | ||
877 | &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, | ||
878 | &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr, | ||
668 | &sensor_dev_attr_temp1_max.dev_attr.attr, | 879 | &sensor_dev_attr_temp1_max.dev_attr.attr, |
880 | &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, | ||
669 | &sensor_dev_attr_temp1_crit.dev_attr.attr, | 881 | &sensor_dev_attr_temp1_crit.dev_attr.attr, |
882 | &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, | ||
883 | &sensor_dev_attr_temp1_emergency.dev_attr.attr, | ||
884 | &sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr, | ||
670 | &sensor_dev_attr_name.dev_attr.attr, | 885 | &sensor_dev_attr_name.dev_attr.attr, |
671 | &sensor_dev_attr_update_rate.dev_attr.attr, | 886 | &sensor_dev_attr_update_rate.dev_attr.attr, |
672 | NULL | 887 | NULL |
673 | }; | 888 | }; |
674 | static struct attribute *hwmon_fan_rpm_attributes[] = { | 889 | static struct attribute *hwmon_fan_rpm_attributes[] = { |
675 | &sensor_dev_attr_fan0_input.dev_attr.attr, | 890 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
676 | NULL | 891 | NULL |
677 | }; | 892 | }; |
678 | static struct attribute *hwmon_pwm_fan_attributes[] = { | 893 | static struct attribute *hwmon_pwm_fan_attributes[] = { |
@@ -717,7 +932,7 @@ nouveau_hwmon_init(struct drm_device *dev) | |||
717 | dev_set_drvdata(hwmon_dev, dev); | 932 | dev_set_drvdata(hwmon_dev, dev); |
718 | 933 | ||
719 | /* default sysfs entries */ | 934 | /* default sysfs entries */ |
720 | ret = sysfs_create_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); | 935 | ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_attrgroup); |
721 | if (ret) { | 936 | if (ret) { |
722 | if (ret) | 937 | if (ret) |
723 | goto error; | 938 | goto error; |
@@ -728,7 +943,7 @@ nouveau_hwmon_init(struct drm_device *dev) | |||
728 | * the gpio entries for pwm fan control even when there's no | 943 | * the gpio entries for pwm fan control even when there's no |
729 | * actual fan connected to it... therm table? */ | 944 | * actual fan connected to it... therm table? */ |
730 | if (therm->fan_get && therm->fan_get(therm) >= 0) { | 945 | if (therm->fan_get && therm->fan_get(therm) >= 0) { |
731 | ret = sysfs_create_group(&dev->pdev->dev.kobj, | 946 | ret = sysfs_create_group(&hwmon_dev->kobj, |
732 | &hwmon_pwm_fan_attrgroup); | 947 | &hwmon_pwm_fan_attrgroup); |
733 | if (ret) | 948 | if (ret) |
734 | goto error; | 949 | goto error; |
@@ -736,7 +951,7 @@ nouveau_hwmon_init(struct drm_device *dev) | |||
736 | 951 | ||
737 | /* if the card can read the fan rpm */ | 952 | /* if the card can read the fan rpm */ |
738 | if (therm->fan_sense(therm) >= 0) { | 953 | if (therm->fan_sense(therm) >= 0) { |
739 | ret = sysfs_create_group(&dev->pdev->dev.kobj, | 954 | ret = sysfs_create_group(&hwmon_dev->kobj, |
740 | &hwmon_fan_rpm_attrgroup); | 955 | &hwmon_fan_rpm_attrgroup); |
741 | if (ret) | 956 | if (ret) |
742 | goto error; | 957 | goto error; |
@@ -764,10 +979,10 @@ nouveau_hwmon_fini(struct drm_device *dev) | |||
764 | struct nouveau_pm *pm = nouveau_pm(dev); | 979 | struct nouveau_pm *pm = nouveau_pm(dev); |
765 | 980 | ||
766 | if (pm->hwmon) { | 981 | if (pm->hwmon) { |
767 | sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); | 982 | sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup); |
768 | sysfs_remove_group(&dev->pdev->dev.kobj, | 983 | sysfs_remove_group(&pm->hwmon->kobj, |
769 | &hwmon_pwm_fan_attrgroup); | 984 | &hwmon_pwm_fan_attrgroup); |
770 | sysfs_remove_group(&dev->pdev->dev.kobj, | 985 | sysfs_remove_group(&pm->hwmon->kobj, |
771 | &hwmon_fan_rpm_attrgroup); | 986 | &hwmon_fan_rpm_attrgroup); |
772 | 987 | ||
773 | hwmon_device_unregister(pm->hwmon); | 988 | hwmon_device_unregister(pm->hwmon); |
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index 39ffc07f906b..7e24cdf1cb39 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c | |||
@@ -490,8 +490,8 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) | |||
490 | /* BIOS scripts usually take care of the backlight, thanks | 490 | /* BIOS scripts usually take care of the backlight, thanks |
491 | * Apple for your consistency. | 491 | * Apple for your consistency. |
492 | */ | 492 | */ |
493 | if (dev->pci_device == 0x0179 || dev->pci_device == 0x0189 || | 493 | if (dev->pci_device == 0x0174 || dev->pci_device == 0x0179 || |
494 | dev->pci_device == 0x0329) { | 494 | dev->pci_device == 0x0189 || dev->pci_device == 0x0329) { |
495 | if (mode == DRM_MODE_DPMS_ON) { | 495 | if (mode == DRM_MODE_DPMS_ON) { |
496 | nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 0, 1 << 31); | 496 | nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 0, 1 << 31); |
497 | nv_mask(device, NV_PCRTC_GPIO_EXT, 3, 1); | 497 | nv_mask(device, NV_PCRTC_GPIO_EXT, 3, 1); |
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c index 4c6e9f83fe82..ad48444c385c 100644 --- a/drivers/gpu/drm/nouveau/nv04_display.c +++ b/drivers/gpu/drm/nouveau/nv04_display.c | |||
@@ -22,6 +22,9 @@ | |||
22 | * Author: Ben Skeggs | 22 | * Author: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/object.h> | ||
26 | #include <core/class.h> | ||
27 | |||
25 | #include <drm/drmP.h> | 28 | #include <drm/drmP.h> |
26 | #include <drm/drm_crtc_helper.h> | 29 | #include <drm/drm_crtc_helper.h> |
27 | 30 | ||
@@ -31,6 +34,8 @@ | |||
31 | #include "nouveau_encoder.h" | 34 | #include "nouveau_encoder.h" |
32 | #include "nouveau_connector.h" | 35 | #include "nouveau_connector.h" |
33 | 36 | ||
37 | #include <subdev/i2c.h> | ||
38 | |||
34 | int | 39 | int |
35 | nv04_display_early_init(struct drm_device *dev) | 40 | nv04_display_early_init(struct drm_device *dev) |
36 | { | 41 | { |
@@ -53,6 +58,7 @@ int | |||
53 | nv04_display_create(struct drm_device *dev) | 58 | nv04_display_create(struct drm_device *dev) |
54 | { | 59 | { |
55 | struct nouveau_drm *drm = nouveau_drm(dev); | 60 | struct nouveau_drm *drm = nouveau_drm(dev); |
61 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | ||
56 | struct dcb_table *dcb = &drm->vbios.dcb; | 62 | struct dcb_table *dcb = &drm->vbios.dcb; |
57 | struct drm_connector *connector, *ct; | 63 | struct drm_connector *connector, *ct; |
58 | struct drm_encoder *encoder; | 64 | struct drm_encoder *encoder; |
@@ -71,6 +77,11 @@ nv04_display_create(struct drm_device *dev) | |||
71 | 77 | ||
72 | nouveau_hw_save_vga_fonts(dev, 1); | 78 | nouveau_hw_save_vga_fonts(dev, 1); |
73 | 79 | ||
80 | ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, 0xd1500000, | ||
81 | NV04_DISP_CLASS, NULL, 0, &disp->core); | ||
82 | if (ret) | ||
83 | return ret; | ||
84 | |||
74 | nv04_crtc_create(dev, 0); | 85 | nv04_crtc_create(dev, 0); |
75 | if (nv_two_heads(dev)) | 86 | if (nv_two_heads(dev)) |
76 | nv04_crtc_create(dev, 1); | 87 | nv04_crtc_create(dev, 1); |
@@ -114,6 +125,11 @@ nv04_display_create(struct drm_device *dev) | |||
114 | } | 125 | } |
115 | } | 126 | } |
116 | 127 | ||
128 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
129 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
130 | nv_encoder->i2c = i2c->find(i2c, nv_encoder->dcb->i2c_index); | ||
131 | } | ||
132 | |||
117 | /* Save previous state */ | 133 | /* Save previous state */ |
118 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | 134 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) |
119 | crtc->funcs->save(crtc); | 135 | crtc->funcs->save(crtc); |
diff --git a/drivers/gpu/drm/nouveau/nv04_display.h b/drivers/gpu/drm/nouveau/nv04_display.h index 45322802e37d..a0a031dad13f 100644 --- a/drivers/gpu/drm/nouveau/nv04_display.h +++ b/drivers/gpu/drm/nouveau/nv04_display.h | |||
@@ -80,6 +80,7 @@ struct nv04_display { | |||
80 | struct nv04_mode_state saved_reg; | 80 | struct nv04_mode_state saved_reg; |
81 | uint32_t saved_vga_font[4][16384]; | 81 | uint32_t saved_vga_font[4][16384]; |
82 | uint32_t dac_users[4]; | 82 | uint32_t dac_users[4]; |
83 | struct nouveau_object *core; | ||
83 | }; | 84 | }; |
84 | 85 | ||
85 | static inline struct nv04_display * | 86 | static inline struct nv04_display * |
diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c index a220b94ba9f2..94eadd1dd10a 100644 --- a/drivers/gpu/drm/nouveau/nv04_fence.c +++ b/drivers/gpu/drm/nouveau/nv04_fence.c | |||
@@ -78,6 +78,9 @@ nv04_fence_context_new(struct nouveau_channel *chan) | |||
78 | struct nv04_fence_chan *fctx = kzalloc(sizeof(*fctx), GFP_KERNEL); | 78 | struct nv04_fence_chan *fctx = kzalloc(sizeof(*fctx), GFP_KERNEL); |
79 | if (fctx) { | 79 | if (fctx) { |
80 | nouveau_fence_context_new(&fctx->base); | 80 | nouveau_fence_context_new(&fctx->base); |
81 | fctx->base.emit = nv04_fence_emit; | ||
82 | fctx->base.sync = nv04_fence_sync; | ||
83 | fctx->base.read = nv04_fence_read; | ||
81 | chan->fence = fctx; | 84 | chan->fence = fctx; |
82 | return 0; | 85 | return 0; |
83 | } | 86 | } |
@@ -104,8 +107,5 @@ nv04_fence_create(struct nouveau_drm *drm) | |||
104 | priv->base.dtor = nv04_fence_destroy; | 107 | priv->base.dtor = nv04_fence_destroy; |
105 | priv->base.context_new = nv04_fence_context_new; | 108 | priv->base.context_new = nv04_fence_context_new; |
106 | priv->base.context_del = nv04_fence_context_del; | 109 | priv->base.context_del = nv04_fence_context_del; |
107 | priv->base.emit = nv04_fence_emit; | ||
108 | priv->base.sync = nv04_fence_sync; | ||
109 | priv->base.read = nv04_fence_read; | ||
110 | return 0; | 110 | return 0; |
111 | } | 111 | } |
diff --git a/drivers/gpu/drm/nouveau/nv10_fence.c b/drivers/gpu/drm/nouveau/nv10_fence.c index 03017f24d593..06f434f03fba 100644 --- a/drivers/gpu/drm/nouveau/nv10_fence.c +++ b/drivers/gpu/drm/nouveau/nv10_fence.c | |||
@@ -27,18 +27,7 @@ | |||
27 | 27 | ||
28 | #include "nouveau_drm.h" | 28 | #include "nouveau_drm.h" |
29 | #include "nouveau_dma.h" | 29 | #include "nouveau_dma.h" |
30 | #include "nouveau_fence.h" | 30 | #include "nv10_fence.h" |
31 | |||
32 | struct nv10_fence_chan { | ||
33 | struct nouveau_fence_chan base; | ||
34 | }; | ||
35 | |||
36 | struct nv10_fence_priv { | ||
37 | struct nouveau_fence_priv base; | ||
38 | struct nouveau_bo *bo; | ||
39 | spinlock_t lock; | ||
40 | u32 sequence; | ||
41 | }; | ||
42 | 31 | ||
43 | int | 32 | int |
44 | nv10_fence_emit(struct nouveau_fence *fence) | 33 | nv10_fence_emit(struct nouveau_fence *fence) |
@@ -61,45 +50,6 @@ nv10_fence_sync(struct nouveau_fence *fence, | |||
61 | return -ENODEV; | 50 | return -ENODEV; |
62 | } | 51 | } |
63 | 52 | ||
64 | int | ||
65 | nv17_fence_sync(struct nouveau_fence *fence, | ||
66 | struct nouveau_channel *prev, struct nouveau_channel *chan) | ||
67 | { | ||
68 | struct nv10_fence_priv *priv = chan->drm->fence; | ||
69 | u32 value; | ||
70 | int ret; | ||
71 | |||
72 | if (!mutex_trylock(&prev->cli->mutex)) | ||
73 | return -EBUSY; | ||
74 | |||
75 | spin_lock(&priv->lock); | ||
76 | value = priv->sequence; | ||
77 | priv->sequence += 2; | ||
78 | spin_unlock(&priv->lock); | ||
79 | |||
80 | ret = RING_SPACE(prev, 5); | ||
81 | if (!ret) { | ||
82 | BEGIN_NV04(prev, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 4); | ||
83 | OUT_RING (prev, NvSema); | ||
84 | OUT_RING (prev, 0); | ||
85 | OUT_RING (prev, value + 0); | ||
86 | OUT_RING (prev, value + 1); | ||
87 | FIRE_RING (prev); | ||
88 | } | ||
89 | |||
90 | if (!ret && !(ret = RING_SPACE(chan, 5))) { | ||
91 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 4); | ||
92 | OUT_RING (chan, NvSema); | ||
93 | OUT_RING (chan, 0); | ||
94 | OUT_RING (chan, value + 1); | ||
95 | OUT_RING (chan, value + 2); | ||
96 | FIRE_RING (chan); | ||
97 | } | ||
98 | |||
99 | mutex_unlock(&prev->cli->mutex); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | u32 | 53 | u32 |
104 | nv10_fence_read(struct nouveau_channel *chan) | 54 | nv10_fence_read(struct nouveau_channel *chan) |
105 | { | 55 | { |
@@ -115,39 +65,20 @@ nv10_fence_context_del(struct nouveau_channel *chan) | |||
115 | kfree(fctx); | 65 | kfree(fctx); |
116 | } | 66 | } |
117 | 67 | ||
118 | static int | 68 | int |
119 | nv10_fence_context_new(struct nouveau_channel *chan) | 69 | nv10_fence_context_new(struct nouveau_channel *chan) |
120 | { | 70 | { |
121 | struct nv10_fence_priv *priv = chan->drm->fence; | ||
122 | struct nv10_fence_chan *fctx; | 71 | struct nv10_fence_chan *fctx; |
123 | int ret = 0; | ||
124 | 72 | ||
125 | fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); | 73 | fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); |
126 | if (!fctx) | 74 | if (!fctx) |
127 | return -ENOMEM; | 75 | return -ENOMEM; |
128 | 76 | ||
129 | nouveau_fence_context_new(&fctx->base); | 77 | nouveau_fence_context_new(&fctx->base); |
130 | 78 | fctx->base.emit = nv10_fence_emit; | |
131 | if (priv->bo) { | 79 | fctx->base.read = nv10_fence_read; |
132 | struct ttm_mem_reg *mem = &priv->bo->bo.mem; | 80 | fctx->base.sync = nv10_fence_sync; |
133 | struct nouveau_object *object; | 81 | return 0; |
134 | u32 start = mem->start * PAGE_SIZE; | ||
135 | u32 limit = mem->start + mem->size - 1; | ||
136 | |||
137 | ret = nouveau_object_new(nv_object(chan->cli), chan->handle, | ||
138 | NvSema, 0x0002, | ||
139 | &(struct nv_dma_class) { | ||
140 | .flags = NV_DMA_TARGET_VRAM | | ||
141 | NV_DMA_ACCESS_RDWR, | ||
142 | .start = start, | ||
143 | .limit = limit, | ||
144 | }, sizeof(struct nv_dma_class), | ||
145 | &object); | ||
146 | } | ||
147 | |||
148 | if (ret) | ||
149 | nv10_fence_context_del(chan); | ||
150 | return ret; | ||
151 | } | 82 | } |
152 | 83 | ||
153 | void | 84 | void |
@@ -162,18 +93,10 @@ nv10_fence_destroy(struct nouveau_drm *drm) | |||
162 | kfree(priv); | 93 | kfree(priv); |
163 | } | 94 | } |
164 | 95 | ||
165 | void nv17_fence_resume(struct nouveau_drm *drm) | ||
166 | { | ||
167 | struct nv10_fence_priv *priv = drm->fence; | ||
168 | |||
169 | nouveau_bo_wr32(priv->bo, 0, priv->sequence); | ||
170 | } | ||
171 | |||
172 | int | 96 | int |
173 | nv10_fence_create(struct nouveau_drm *drm) | 97 | nv10_fence_create(struct nouveau_drm *drm) |
174 | { | 98 | { |
175 | struct nv10_fence_priv *priv; | 99 | struct nv10_fence_priv *priv; |
176 | int ret = 0; | ||
177 | 100 | ||
178 | priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL); | 101 | priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL); |
179 | if (!priv) | 102 | if (!priv) |
@@ -182,33 +105,6 @@ nv10_fence_create(struct nouveau_drm *drm) | |||
182 | priv->base.dtor = nv10_fence_destroy; | 105 | priv->base.dtor = nv10_fence_destroy; |
183 | priv->base.context_new = nv10_fence_context_new; | 106 | priv->base.context_new = nv10_fence_context_new; |
184 | priv->base.context_del = nv10_fence_context_del; | 107 | priv->base.context_del = nv10_fence_context_del; |
185 | priv->base.emit = nv10_fence_emit; | ||
186 | priv->base.read = nv10_fence_read; | ||
187 | priv->base.sync = nv10_fence_sync; | ||
188 | spin_lock_init(&priv->lock); | 108 | spin_lock_init(&priv->lock); |
189 | 109 | return 0; | |
190 | if (nv_device(drm->device)->chipset >= 0x17) { | ||
191 | ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, | ||
192 | 0, 0x0000, NULL, &priv->bo); | ||
193 | if (!ret) { | ||
194 | ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); | ||
195 | if (!ret) { | ||
196 | ret = nouveau_bo_map(priv->bo); | ||
197 | if (ret) | ||
198 | nouveau_bo_unpin(priv->bo); | ||
199 | } | ||
200 | if (ret) | ||
201 | nouveau_bo_ref(NULL, &priv->bo); | ||
202 | } | ||
203 | |||
204 | if (ret == 0) { | ||
205 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); | ||
206 | priv->base.sync = nv17_fence_sync; | ||
207 | priv->base.resume = nv17_fence_resume; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | if (ret) | ||
212 | nv10_fence_destroy(drm); | ||
213 | return ret; | ||
214 | } | 110 | } |
diff --git a/drivers/gpu/drm/nouveau/nv10_fence.h b/drivers/gpu/drm/nouveau/nv10_fence.h new file mode 100644 index 000000000000..e5d9204826c2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv10_fence.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef __NV10_FENCE_H_ | ||
2 | #define __NV10_FENCE_H_ | ||
3 | |||
4 | #include <core/os.h> | ||
5 | #include "nouveau_fence.h" | ||
6 | #include "nouveau_bo.h" | ||
7 | |||
8 | struct nv10_fence_chan { | ||
9 | struct nouveau_fence_chan base; | ||
10 | }; | ||
11 | |||
12 | struct nv10_fence_priv { | ||
13 | struct nouveau_fence_priv base; | ||
14 | struct nouveau_bo *bo; | ||
15 | spinlock_t lock; | ||
16 | u32 sequence; | ||
17 | }; | ||
18 | |||
19 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/nv17_fence.c b/drivers/gpu/drm/nouveau/nv17_fence.c new file mode 100644 index 000000000000..8e47a9bae8c3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv17_fence.c | |||
@@ -0,0 +1,149 @@ | |||
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 <bskeggs@redhat.com> | ||
23 | */ | ||
24 | |||
25 | #include <core/object.h> | ||
26 | #include <core/class.h> | ||
27 | |||
28 | #include "nouveau_drm.h" | ||
29 | #include "nouveau_dma.h" | ||
30 | #include "nv10_fence.h" | ||
31 | |||
32 | int | ||
33 | nv17_fence_sync(struct nouveau_fence *fence, | ||
34 | struct nouveau_channel *prev, struct nouveau_channel *chan) | ||
35 | { | ||
36 | struct nv10_fence_priv *priv = chan->drm->fence; | ||
37 | u32 value; | ||
38 | int ret; | ||
39 | |||
40 | if (!mutex_trylock(&prev->cli->mutex)) | ||
41 | return -EBUSY; | ||
42 | |||
43 | spin_lock(&priv->lock); | ||
44 | value = priv->sequence; | ||
45 | priv->sequence += 2; | ||
46 | spin_unlock(&priv->lock); | ||
47 | |||
48 | ret = RING_SPACE(prev, 5); | ||
49 | if (!ret) { | ||
50 | BEGIN_NV04(prev, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 4); | ||
51 | OUT_RING (prev, NvSema); | ||
52 | OUT_RING (prev, 0); | ||
53 | OUT_RING (prev, value + 0); | ||
54 | OUT_RING (prev, value + 1); | ||
55 | FIRE_RING (prev); | ||
56 | } | ||
57 | |||
58 | if (!ret && !(ret = RING_SPACE(chan, 5))) { | ||
59 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 4); | ||
60 | OUT_RING (chan, NvSema); | ||
61 | OUT_RING (chan, 0); | ||
62 | OUT_RING (chan, value + 1); | ||
63 | OUT_RING (chan, value + 2); | ||
64 | FIRE_RING (chan); | ||
65 | } | ||
66 | |||
67 | mutex_unlock(&prev->cli->mutex); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int | ||
72 | nv17_fence_context_new(struct nouveau_channel *chan) | ||
73 | { | ||
74 | struct nv10_fence_priv *priv = chan->drm->fence; | ||
75 | struct nv10_fence_chan *fctx; | ||
76 | struct ttm_mem_reg *mem = &priv->bo->bo.mem; | ||
77 | struct nouveau_object *object; | ||
78 | u32 start = mem->start * PAGE_SIZE; | ||
79 | u32 limit = mem->start + mem->size - 1; | ||
80 | int ret = 0; | ||
81 | |||
82 | fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); | ||
83 | if (!fctx) | ||
84 | return -ENOMEM; | ||
85 | |||
86 | nouveau_fence_context_new(&fctx->base); | ||
87 | fctx->base.emit = nv10_fence_emit; | ||
88 | fctx->base.read = nv10_fence_read; | ||
89 | fctx->base.sync = nv17_fence_sync; | ||
90 | |||
91 | ret = nouveau_object_new(nv_object(chan->cli), chan->handle, | ||
92 | NvSema, 0x0002, | ||
93 | &(struct nv_dma_class) { | ||
94 | .flags = NV_DMA_TARGET_VRAM | | ||
95 | NV_DMA_ACCESS_RDWR, | ||
96 | .start = start, | ||
97 | .limit = limit, | ||
98 | }, sizeof(struct nv_dma_class), | ||
99 | &object); | ||
100 | if (ret) | ||
101 | nv10_fence_context_del(chan); | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | void | ||
106 | nv17_fence_resume(struct nouveau_drm *drm) | ||
107 | { | ||
108 | struct nv10_fence_priv *priv = drm->fence; | ||
109 | |||
110 | nouveau_bo_wr32(priv->bo, 0, priv->sequence); | ||
111 | } | ||
112 | |||
113 | int | ||
114 | nv17_fence_create(struct nouveau_drm *drm) | ||
115 | { | ||
116 | struct nv10_fence_priv *priv; | ||
117 | int ret = 0; | ||
118 | |||
119 | priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
120 | if (!priv) | ||
121 | return -ENOMEM; | ||
122 | |||
123 | priv->base.dtor = nv10_fence_destroy; | ||
124 | priv->base.resume = nv17_fence_resume; | ||
125 | priv->base.context_new = nv17_fence_context_new; | ||
126 | priv->base.context_del = nv10_fence_context_del; | ||
127 | spin_lock_init(&priv->lock); | ||
128 | |||
129 | ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, | ||
130 | 0, 0x0000, NULL, &priv->bo); | ||
131 | if (!ret) { | ||
132 | ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); | ||
133 | if (!ret) { | ||
134 | ret = nouveau_bo_map(priv->bo); | ||
135 | if (ret) | ||
136 | nouveau_bo_unpin(priv->bo); | ||
137 | } | ||
138 | if (ret) | ||
139 | nouveau_bo_ref(NULL, &priv->bo); | ||
140 | } | ||
141 | |||
142 | if (ret) { | ||
143 | nv10_fence_destroy(drm); | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); | ||
148 | return ret; | ||
149 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index d4cbea19b890..45624c37e29f 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <subdev/timer.h> | 43 | #include <subdev/timer.h> |
44 | #include <subdev/bar.h> | 44 | #include <subdev/bar.h> |
45 | #include <subdev/fb.h> | 45 | #include <subdev/fb.h> |
46 | #include <subdev/i2c.h> | ||
46 | 47 | ||
47 | #define EVO_DMA_NR 9 | 48 | #define EVO_DMA_NR 9 |
48 | 49 | ||
@@ -433,7 +434,10 @@ evo_kick(u32 *push, void *evoc) | |||
433 | static bool | 434 | static bool |
434 | evo_sync_wait(void *data) | 435 | evo_sync_wait(void *data) |
435 | { | 436 | { |
436 | return nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000; | 437 | if (nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000) |
438 | return true; | ||
439 | usleep_range(1, 2); | ||
440 | return false; | ||
437 | } | 441 | } |
438 | 442 | ||
439 | static int | 443 | static int |
@@ -512,7 +516,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
512 | if (ret) | 516 | if (ret) |
513 | return ret; | 517 | return ret; |
514 | 518 | ||
515 | if (nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { | 519 | if (nv_mclass(chan->object) < NV84_CHANNEL_IND_CLASS) { |
516 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); | 520 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); |
517 | OUT_RING (chan, NvEvoSema0 + nv_crtc->index); | 521 | OUT_RING (chan, NvEvoSema0 + nv_crtc->index); |
518 | OUT_RING (chan, sync->sem.offset); | 522 | OUT_RING (chan, sync->sem.offset); |
@@ -522,24 +526,36 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
522 | OUT_RING (chan, sync->sem.offset ^ 0x10); | 526 | OUT_RING (chan, sync->sem.offset ^ 0x10); |
523 | OUT_RING (chan, 0x74b1e000); | 527 | OUT_RING (chan, 0x74b1e000); |
524 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); | 528 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); |
525 | if (nv_mclass(chan->object) < NV84_CHANNEL_DMA_CLASS) | 529 | OUT_RING (chan, NvSema); |
526 | OUT_RING (chan, NvSema); | 530 | } else |
527 | else | 531 | if (nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { |
528 | OUT_RING (chan, chan->vram); | 532 | u64 offset = nv84_fence_crtc(chan, nv_crtc->index); |
533 | offset += sync->sem.offset; | ||
534 | |||
535 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | ||
536 | OUT_RING (chan, upper_32_bits(offset)); | ||
537 | OUT_RING (chan, lower_32_bits(offset)); | ||
538 | OUT_RING (chan, 0xf00d0000 | sync->sem.value); | ||
539 | OUT_RING (chan, 0x00000002); | ||
540 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | ||
541 | OUT_RING (chan, upper_32_bits(offset)); | ||
542 | OUT_RING (chan, lower_32_bits(offset ^ 0x10)); | ||
543 | OUT_RING (chan, 0x74b1e000); | ||
544 | OUT_RING (chan, 0x00000001); | ||
529 | } else { | 545 | } else { |
530 | u64 offset = nvc0_fence_crtc(chan, nv_crtc->index); | 546 | u64 offset = nv84_fence_crtc(chan, nv_crtc->index); |
531 | offset += sync->sem.offset; | 547 | offset += sync->sem.offset; |
532 | 548 | ||
533 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 549 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); |
534 | OUT_RING (chan, upper_32_bits(offset)); | 550 | OUT_RING (chan, upper_32_bits(offset)); |
535 | OUT_RING (chan, lower_32_bits(offset)); | 551 | OUT_RING (chan, lower_32_bits(offset)); |
536 | OUT_RING (chan, 0xf00d0000 | sync->sem.value); | 552 | OUT_RING (chan, 0xf00d0000 | sync->sem.value); |
537 | OUT_RING (chan, 0x1002); | 553 | OUT_RING (chan, 0x00001002); |
538 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 554 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); |
539 | OUT_RING (chan, upper_32_bits(offset)); | 555 | OUT_RING (chan, upper_32_bits(offset)); |
540 | OUT_RING (chan, lower_32_bits(offset ^ 0x10)); | 556 | OUT_RING (chan, lower_32_bits(offset ^ 0x10)); |
541 | OUT_RING (chan, 0x74b1e000); | 557 | OUT_RING (chan, 0x74b1e000); |
542 | OUT_RING (chan, 0x1001); | 558 | OUT_RING (chan, 0x00001001); |
543 | } | 559 | } |
544 | 560 | ||
545 | FIRE_RING (chan); | 561 | FIRE_RING (chan); |
@@ -1552,20 +1568,23 @@ static const struct drm_encoder_funcs nv50_dac_func = { | |||
1552 | static int | 1568 | static int |
1553 | nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) | 1569 | nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) |
1554 | { | 1570 | { |
1555 | struct drm_device *dev = connector->dev; | 1571 | struct nouveau_drm *drm = nouveau_drm(connector->dev); |
1572 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | ||
1556 | struct nouveau_encoder *nv_encoder; | 1573 | struct nouveau_encoder *nv_encoder; |
1557 | struct drm_encoder *encoder; | 1574 | struct drm_encoder *encoder; |
1575 | int type = DRM_MODE_ENCODER_DAC; | ||
1558 | 1576 | ||
1559 | nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); | 1577 | nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); |
1560 | if (!nv_encoder) | 1578 | if (!nv_encoder) |
1561 | return -ENOMEM; | 1579 | return -ENOMEM; |
1562 | nv_encoder->dcb = dcbe; | 1580 | nv_encoder->dcb = dcbe; |
1563 | nv_encoder->or = ffs(dcbe->or) - 1; | 1581 | nv_encoder->or = ffs(dcbe->or) - 1; |
1582 | nv_encoder->i2c = i2c->find(i2c, dcbe->i2c_index); | ||
1564 | 1583 | ||
1565 | encoder = to_drm_encoder(nv_encoder); | 1584 | encoder = to_drm_encoder(nv_encoder); |
1566 | encoder->possible_crtcs = dcbe->heads; | 1585 | encoder->possible_crtcs = dcbe->heads; |
1567 | encoder->possible_clones = 0; | 1586 | encoder->possible_clones = 0; |
1568 | drm_encoder_init(dev, encoder, &nv50_dac_func, DRM_MODE_ENCODER_DAC); | 1587 | drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type); |
1569 | drm_encoder_helper_add(encoder, &nv50_dac_hfunc); | 1588 | drm_encoder_helper_add(encoder, &nv50_dac_hfunc); |
1570 | 1589 | ||
1571 | drm_mode_connector_attach_encoder(connector, encoder); | 1590 | drm_mode_connector_attach_encoder(connector, encoder); |
@@ -1674,9 +1693,6 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) | |||
1674 | } | 1693 | } |
1675 | 1694 | ||
1676 | nv_call(disp->core, NV50_DISP_SOR_PWR + or, (mode == DRM_MODE_DPMS_ON)); | 1695 | nv_call(disp->core, NV50_DISP_SOR_PWR + or, (mode == DRM_MODE_DPMS_ON)); |
1677 | |||
1678 | if (nv_encoder->dcb->type == DCB_OUTPUT_DP) | ||
1679 | nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, disp->core); | ||
1680 | } | 1696 | } |
1681 | 1697 | ||
1682 | static bool | 1698 | static bool |
@@ -1733,14 +1749,6 @@ nv50_sor_disconnect(struct drm_encoder *encoder) | |||
1733 | } | 1749 | } |
1734 | 1750 | ||
1735 | static void | 1751 | static void |
1736 | nv50_sor_prepare(struct drm_encoder *encoder) | ||
1737 | { | ||
1738 | nv50_sor_disconnect(encoder); | ||
1739 | if (nouveau_encoder(encoder)->dcb->type == DCB_OUTPUT_DP) | ||
1740 | evo_sync(encoder->dev); | ||
1741 | } | ||
1742 | |||
1743 | static void | ||
1744 | nv50_sor_commit(struct drm_encoder *encoder) | 1752 | nv50_sor_commit(struct drm_encoder *encoder) |
1745 | { | 1753 | { |
1746 | } | 1754 | } |
@@ -1835,8 +1843,13 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, | |||
1835 | push = evo_wait(nv50_mast(dev), 8); | 1843 | push = evo_wait(nv50_mast(dev), 8); |
1836 | if (push) { | 1844 | if (push) { |
1837 | if (nv50_vers(mast) < NVD0_DISP_CLASS) { | 1845 | if (nv50_vers(mast) < NVD0_DISP_CLASS) { |
1846 | u32 ctrl = (depth << 16) | (proto << 8) | owner; | ||
1847 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
1848 | ctrl |= 0x00001000; | ||
1849 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
1850 | ctrl |= 0x00002000; | ||
1838 | evo_mthd(push, 0x0600 + (nv_encoder->or * 0x040), 1); | 1851 | evo_mthd(push, 0x0600 + (nv_encoder->or * 0x040), 1); |
1839 | evo_data(push, (depth << 16) | (proto << 8) | owner); | 1852 | evo_data(push, ctrl); |
1840 | } else { | 1853 | } else { |
1841 | u32 magic = 0x31ec6000 | (nv_crtc->index << 25); | 1854 | u32 magic = 0x31ec6000 | (nv_crtc->index << 25); |
1842 | u32 syncs = 0x00000001; | 1855 | u32 syncs = 0x00000001; |
@@ -1872,7 +1885,7 @@ nv50_sor_destroy(struct drm_encoder *encoder) | |||
1872 | static const struct drm_encoder_helper_funcs nv50_sor_hfunc = { | 1885 | static const struct drm_encoder_helper_funcs nv50_sor_hfunc = { |
1873 | .dpms = nv50_sor_dpms, | 1886 | .dpms = nv50_sor_dpms, |
1874 | .mode_fixup = nv50_sor_mode_fixup, | 1887 | .mode_fixup = nv50_sor_mode_fixup, |
1875 | .prepare = nv50_sor_prepare, | 1888 | .prepare = nv50_sor_disconnect, |
1876 | .commit = nv50_sor_commit, | 1889 | .commit = nv50_sor_commit, |
1877 | .mode_set = nv50_sor_mode_set, | 1890 | .mode_set = nv50_sor_mode_set, |
1878 | .disable = nv50_sor_disconnect, | 1891 | .disable = nv50_sor_disconnect, |
@@ -1886,21 +1899,33 @@ static const struct drm_encoder_funcs nv50_sor_func = { | |||
1886 | static int | 1899 | static int |
1887 | nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) | 1900 | nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) |
1888 | { | 1901 | { |
1889 | struct drm_device *dev = connector->dev; | 1902 | struct nouveau_drm *drm = nouveau_drm(connector->dev); |
1903 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | ||
1890 | struct nouveau_encoder *nv_encoder; | 1904 | struct nouveau_encoder *nv_encoder; |
1891 | struct drm_encoder *encoder; | 1905 | struct drm_encoder *encoder; |
1906 | int type; | ||
1907 | |||
1908 | switch (dcbe->type) { | ||
1909 | case DCB_OUTPUT_LVDS: type = DRM_MODE_ENCODER_LVDS; break; | ||
1910 | case DCB_OUTPUT_TMDS: | ||
1911 | case DCB_OUTPUT_DP: | ||
1912 | default: | ||
1913 | type = DRM_MODE_ENCODER_TMDS; | ||
1914 | break; | ||
1915 | } | ||
1892 | 1916 | ||
1893 | nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); | 1917 | nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); |
1894 | if (!nv_encoder) | 1918 | if (!nv_encoder) |
1895 | return -ENOMEM; | 1919 | return -ENOMEM; |
1896 | nv_encoder->dcb = dcbe; | 1920 | nv_encoder->dcb = dcbe; |
1897 | nv_encoder->or = ffs(dcbe->or) - 1; | 1921 | nv_encoder->or = ffs(dcbe->or) - 1; |
1922 | nv_encoder->i2c = i2c->find(i2c, dcbe->i2c_index); | ||
1898 | nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; | 1923 | nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; |
1899 | 1924 | ||
1900 | encoder = to_drm_encoder(nv_encoder); | 1925 | encoder = to_drm_encoder(nv_encoder); |
1901 | encoder->possible_crtcs = dcbe->heads; | 1926 | encoder->possible_crtcs = dcbe->heads; |
1902 | encoder->possible_clones = 0; | 1927 | encoder->possible_clones = 0; |
1903 | drm_encoder_init(dev, encoder, &nv50_sor_func, DRM_MODE_ENCODER_TMDS); | 1928 | drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type); |
1904 | drm_encoder_helper_add(encoder, &nv50_sor_hfunc); | 1929 | drm_encoder_helper_add(encoder, &nv50_sor_hfunc); |
1905 | 1930 | ||
1906 | drm_mode_connector_attach_encoder(connector, encoder); | 1931 | drm_mode_connector_attach_encoder(connector, encoder); |
@@ -1908,6 +1933,184 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) | |||
1908 | } | 1933 | } |
1909 | 1934 | ||
1910 | /****************************************************************************** | 1935 | /****************************************************************************** |
1936 | * PIOR | ||
1937 | *****************************************************************************/ | ||
1938 | |||
1939 | static void | ||
1940 | nv50_pior_dpms(struct drm_encoder *encoder, int mode) | ||
1941 | { | ||
1942 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
1943 | struct nv50_disp *disp = nv50_disp(encoder->dev); | ||
1944 | u32 mthd = (nv_encoder->dcb->type << 12) | nv_encoder->or; | ||
1945 | u32 ctrl = (mode == DRM_MODE_DPMS_ON); | ||
1946 | nv_call(disp->core, NV50_DISP_PIOR_PWR + mthd, ctrl); | ||
1947 | } | ||
1948 | |||
1949 | static bool | ||
1950 | nv50_pior_mode_fixup(struct drm_encoder *encoder, | ||
1951 | const struct drm_display_mode *mode, | ||
1952 | struct drm_display_mode *adjusted_mode) | ||
1953 | { | ||
1954 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
1955 | struct nouveau_connector *nv_connector; | ||
1956 | |||
1957 | nv_connector = nouveau_encoder_connector_get(nv_encoder); | ||
1958 | if (nv_connector && nv_connector->native_mode) { | ||
1959 | if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { | ||
1960 | int id = adjusted_mode->base.id; | ||
1961 | *adjusted_mode = *nv_connector->native_mode; | ||
1962 | adjusted_mode->base.id = id; | ||
1963 | } | ||
1964 | } | ||
1965 | |||
1966 | adjusted_mode->clock *= 2; | ||
1967 | return true; | ||
1968 | } | ||
1969 | |||
1970 | static void | ||
1971 | nv50_pior_commit(struct drm_encoder *encoder) | ||
1972 | { | ||
1973 | } | ||
1974 | |||
1975 | static void | ||
1976 | nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, | ||
1977 | struct drm_display_mode *adjusted_mode) | ||
1978 | { | ||
1979 | struct nv50_mast *mast = nv50_mast(encoder->dev); | ||
1980 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
1981 | struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); | ||
1982 | struct nouveau_connector *nv_connector; | ||
1983 | u8 owner = 1 << nv_crtc->index; | ||
1984 | u8 proto, depth; | ||
1985 | u32 *push; | ||
1986 | |||
1987 | nv_connector = nouveau_encoder_connector_get(nv_encoder); | ||
1988 | switch (nv_connector->base.display_info.bpc) { | ||
1989 | case 10: depth = 0x6; break; | ||
1990 | case 8: depth = 0x5; break; | ||
1991 | case 6: depth = 0x2; break; | ||
1992 | default: depth = 0x0; break; | ||
1993 | } | ||
1994 | |||
1995 | switch (nv_encoder->dcb->type) { | ||
1996 | case DCB_OUTPUT_TMDS: | ||
1997 | case DCB_OUTPUT_DP: | ||
1998 | proto = 0x0; | ||
1999 | break; | ||
2000 | default: | ||
2001 | BUG_ON(1); | ||
2002 | break; | ||
2003 | } | ||
2004 | |||
2005 | nv50_pior_dpms(encoder, DRM_MODE_DPMS_ON); | ||
2006 | |||
2007 | push = evo_wait(mast, 8); | ||
2008 | if (push) { | ||
2009 | if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { | ||
2010 | u32 ctrl = (depth << 16) | (proto << 8) | owner; | ||
2011 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
2012 | ctrl |= 0x00001000; | ||
2013 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
2014 | ctrl |= 0x00002000; | ||
2015 | evo_mthd(push, 0x0700 + (nv_encoder->or * 0x040), 1); | ||
2016 | evo_data(push, ctrl); | ||
2017 | } | ||
2018 | |||
2019 | evo_kick(push, mast); | ||
2020 | } | ||
2021 | |||
2022 | nv_encoder->crtc = encoder->crtc; | ||
2023 | } | ||
2024 | |||
2025 | static void | ||
2026 | nv50_pior_disconnect(struct drm_encoder *encoder) | ||
2027 | { | ||
2028 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
2029 | struct nv50_mast *mast = nv50_mast(encoder->dev); | ||
2030 | const int or = nv_encoder->or; | ||
2031 | u32 *push; | ||
2032 | |||
2033 | if (nv_encoder->crtc) { | ||
2034 | nv50_crtc_prepare(nv_encoder->crtc); | ||
2035 | |||
2036 | push = evo_wait(mast, 4); | ||
2037 | if (push) { | ||
2038 | if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { | ||
2039 | evo_mthd(push, 0x0700 + (or * 0x040), 1); | ||
2040 | evo_data(push, 0x00000000); | ||
2041 | } | ||
2042 | |||
2043 | evo_mthd(push, 0x0080, 1); | ||
2044 | evo_data(push, 0x00000000); | ||
2045 | evo_kick(push, mast); | ||
2046 | } | ||
2047 | } | ||
2048 | |||
2049 | nv_encoder->crtc = NULL; | ||
2050 | } | ||
2051 | |||
2052 | static void | ||
2053 | nv50_pior_destroy(struct drm_encoder *encoder) | ||
2054 | { | ||
2055 | drm_encoder_cleanup(encoder); | ||
2056 | kfree(encoder); | ||
2057 | } | ||
2058 | |||
2059 | static const struct drm_encoder_helper_funcs nv50_pior_hfunc = { | ||
2060 | .dpms = nv50_pior_dpms, | ||
2061 | .mode_fixup = nv50_pior_mode_fixup, | ||
2062 | .prepare = nv50_pior_disconnect, | ||
2063 | .commit = nv50_pior_commit, | ||
2064 | .mode_set = nv50_pior_mode_set, | ||
2065 | .disable = nv50_pior_disconnect, | ||
2066 | .get_crtc = nv50_display_crtc_get, | ||
2067 | }; | ||
2068 | |||
2069 | static const struct drm_encoder_funcs nv50_pior_func = { | ||
2070 | .destroy = nv50_pior_destroy, | ||
2071 | }; | ||
2072 | |||
2073 | static int | ||
2074 | nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) | ||
2075 | { | ||
2076 | struct nouveau_drm *drm = nouveau_drm(connector->dev); | ||
2077 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | ||
2078 | struct nouveau_i2c_port *ddc = NULL; | ||
2079 | struct nouveau_encoder *nv_encoder; | ||
2080 | struct drm_encoder *encoder; | ||
2081 | int type; | ||
2082 | |||
2083 | switch (dcbe->type) { | ||
2084 | case DCB_OUTPUT_TMDS: | ||
2085 | ddc = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(dcbe->extdev)); | ||
2086 | type = DRM_MODE_ENCODER_TMDS; | ||
2087 | break; | ||
2088 | case DCB_OUTPUT_DP: | ||
2089 | ddc = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(dcbe->extdev)); | ||
2090 | type = DRM_MODE_ENCODER_TMDS; | ||
2091 | break; | ||
2092 | default: | ||
2093 | return -ENODEV; | ||
2094 | } | ||
2095 | |||
2096 | nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); | ||
2097 | if (!nv_encoder) | ||
2098 | return -ENOMEM; | ||
2099 | nv_encoder->dcb = dcbe; | ||
2100 | nv_encoder->or = ffs(dcbe->or) - 1; | ||
2101 | nv_encoder->i2c = ddc; | ||
2102 | |||
2103 | encoder = to_drm_encoder(nv_encoder); | ||
2104 | encoder->possible_crtcs = dcbe->heads; | ||
2105 | encoder->possible_clones = 0; | ||
2106 | drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type); | ||
2107 | drm_encoder_helper_add(encoder, &nv50_pior_hfunc); | ||
2108 | |||
2109 | drm_mode_connector_attach_encoder(connector, encoder); | ||
2110 | return 0; | ||
2111 | } | ||
2112 | |||
2113 | /****************************************************************************** | ||
1911 | * Init | 2114 | * Init |
1912 | *****************************************************************************/ | 2115 | *****************************************************************************/ |
1913 | void | 2116 | void |
@@ -1923,7 +2126,7 @@ nv50_display_init(struct drm_device *dev) | |||
1923 | evo_mthd(push, 0x0088, 1); | 2126 | evo_mthd(push, 0x0088, 1); |
1924 | evo_data(push, NvEvoSync); | 2127 | evo_data(push, NvEvoSync); |
1925 | evo_kick(push, nv50_mast(dev)); | 2128 | evo_kick(push, nv50_mast(dev)); |
1926 | return evo_sync(dev); | 2129 | return 0; |
1927 | } | 2130 | } |
1928 | 2131 | ||
1929 | return -EBUSY; | 2132 | return -EBUSY; |
@@ -2029,25 +2232,28 @@ nv50_display_create(struct drm_device *dev) | |||
2029 | if (IS_ERR(connector)) | 2232 | if (IS_ERR(connector)) |
2030 | continue; | 2233 | continue; |
2031 | 2234 | ||
2032 | if (dcbe->location != DCB_LOC_ON_CHIP) { | 2235 | if (dcbe->location == DCB_LOC_ON_CHIP) { |
2033 | NV_WARN(drm, "skipping off-chip encoder %d/%d\n", | 2236 | switch (dcbe->type) { |
2034 | dcbe->type, ffs(dcbe->or) - 1); | 2237 | case DCB_OUTPUT_TMDS: |
2035 | continue; | 2238 | case DCB_OUTPUT_LVDS: |
2239 | case DCB_OUTPUT_DP: | ||
2240 | ret = nv50_sor_create(connector, dcbe); | ||
2241 | break; | ||
2242 | case DCB_OUTPUT_ANALOG: | ||
2243 | ret = nv50_dac_create(connector, dcbe); | ||
2244 | break; | ||
2245 | default: | ||
2246 | ret = -ENODEV; | ||
2247 | break; | ||
2248 | } | ||
2249 | } else { | ||
2250 | ret = nv50_pior_create(connector, dcbe); | ||
2036 | } | 2251 | } |
2037 | 2252 | ||
2038 | switch (dcbe->type) { | 2253 | if (ret) { |
2039 | case DCB_OUTPUT_TMDS: | 2254 | NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n", |
2040 | case DCB_OUTPUT_LVDS: | 2255 | dcbe->location, dcbe->type, |
2041 | case DCB_OUTPUT_DP: | 2256 | ffs(dcbe->or) - 1, ret); |
2042 | nv50_sor_create(connector, dcbe); | ||
2043 | break; | ||
2044 | case DCB_OUTPUT_ANALOG: | ||
2045 | nv50_dac_create(connector, dcbe); | ||
2046 | break; | ||
2047 | default: | ||
2048 | NV_WARN(drm, "skipping unsupported encoder %d/%d\n", | ||
2049 | dcbe->type, ffs(dcbe->or) - 1); | ||
2050 | continue; | ||
2051 | } | 2257 | } |
2052 | } | 2258 | } |
2053 | 2259 | ||
diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c index d889f3ac0d41..f9701e567db8 100644 --- a/drivers/gpu/drm/nouveau/nv50_fence.c +++ b/drivers/gpu/drm/nouveau/nv50_fence.c | |||
@@ -27,27 +27,16 @@ | |||
27 | 27 | ||
28 | #include "nouveau_drm.h" | 28 | #include "nouveau_drm.h" |
29 | #include "nouveau_dma.h" | 29 | #include "nouveau_dma.h" |
30 | #include "nouveau_fence.h" | 30 | #include "nv10_fence.h" |
31 | 31 | ||
32 | #include "nv50_display.h" | 32 | #include "nv50_display.h" |
33 | 33 | ||
34 | struct nv50_fence_chan { | ||
35 | struct nouveau_fence_chan base; | ||
36 | }; | ||
37 | |||
38 | struct nv50_fence_priv { | ||
39 | struct nouveau_fence_priv base; | ||
40 | struct nouveau_bo *bo; | ||
41 | spinlock_t lock; | ||
42 | u32 sequence; | ||
43 | }; | ||
44 | |||
45 | static int | 34 | static int |
46 | nv50_fence_context_new(struct nouveau_channel *chan) | 35 | nv50_fence_context_new(struct nouveau_channel *chan) |
47 | { | 36 | { |
48 | struct drm_device *dev = chan->drm->dev; | 37 | struct drm_device *dev = chan->drm->dev; |
49 | struct nv50_fence_priv *priv = chan->drm->fence; | 38 | struct nv10_fence_priv *priv = chan->drm->fence; |
50 | struct nv50_fence_chan *fctx; | 39 | struct nv10_fence_chan *fctx; |
51 | struct ttm_mem_reg *mem = &priv->bo->bo.mem; | 40 | struct ttm_mem_reg *mem = &priv->bo->bo.mem; |
52 | struct nouveau_object *object; | 41 | struct nouveau_object *object; |
53 | int ret, i; | 42 | int ret, i; |
@@ -57,6 +46,9 @@ nv50_fence_context_new(struct nouveau_channel *chan) | |||
57 | return -ENOMEM; | 46 | return -ENOMEM; |
58 | 47 | ||
59 | nouveau_fence_context_new(&fctx->base); | 48 | nouveau_fence_context_new(&fctx->base); |
49 | fctx->base.emit = nv10_fence_emit; | ||
50 | fctx->base.read = nv10_fence_read; | ||
51 | fctx->base.sync = nv17_fence_sync; | ||
60 | 52 | ||
61 | ret = nouveau_object_new(nv_object(chan->cli), chan->handle, | 53 | ret = nouveau_object_new(nv_object(chan->cli), chan->handle, |
62 | NvSema, 0x0002, | 54 | NvSema, 0x0002, |
@@ -91,7 +83,7 @@ nv50_fence_context_new(struct nouveau_channel *chan) | |||
91 | int | 83 | int |
92 | nv50_fence_create(struct nouveau_drm *drm) | 84 | nv50_fence_create(struct nouveau_drm *drm) |
93 | { | 85 | { |
94 | struct nv50_fence_priv *priv; | 86 | struct nv10_fence_priv *priv; |
95 | int ret = 0; | 87 | int ret = 0; |
96 | 88 | ||
97 | priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL); | 89 | priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL); |
@@ -99,11 +91,9 @@ nv50_fence_create(struct nouveau_drm *drm) | |||
99 | return -ENOMEM; | 91 | return -ENOMEM; |
100 | 92 | ||
101 | priv->base.dtor = nv10_fence_destroy; | 93 | priv->base.dtor = nv10_fence_destroy; |
94 | priv->base.resume = nv17_fence_resume; | ||
102 | priv->base.context_new = nv50_fence_context_new; | 95 | priv->base.context_new = nv50_fence_context_new; |
103 | priv->base.context_del = nv10_fence_context_del; | 96 | priv->base.context_del = nv10_fence_context_del; |
104 | priv->base.emit = nv10_fence_emit; | ||
105 | priv->base.read = nv10_fence_read; | ||
106 | priv->base.sync = nv17_fence_sync; | ||
107 | spin_lock_init(&priv->lock); | 97 | spin_lock_init(&priv->lock); |
108 | 98 | ||
109 | ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, | 99 | ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, |
@@ -119,13 +109,11 @@ nv50_fence_create(struct nouveau_drm *drm) | |||
119 | nouveau_bo_ref(NULL, &priv->bo); | 109 | nouveau_bo_ref(NULL, &priv->bo); |
120 | } | 110 | } |
121 | 111 | ||
122 | if (ret == 0) { | 112 | if (ret) { |
123 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); | 113 | nv10_fence_destroy(drm); |
124 | priv->base.sync = nv17_fence_sync; | 114 | return ret; |
125 | priv->base.resume = nv17_fence_resume; | ||
126 | } | 115 | } |
127 | 116 | ||
128 | if (ret) | 117 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); |
129 | nv10_fence_destroy(drm); | ||
130 | return ret; | 118 | return ret; |
131 | } | 119 | } |
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index c686650584b6..9fd475c89820 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c | |||
@@ -23,6 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/object.h> | 25 | #include <core/object.h> |
26 | #include <core/client.h> | ||
26 | #include <core/class.h> | 27 | #include <core/class.h> |
27 | 28 | ||
28 | #include <engine/fifo.h> | 29 | #include <engine/fifo.h> |
@@ -33,79 +34,115 @@ | |||
33 | 34 | ||
34 | #include "nv50_display.h" | 35 | #include "nv50_display.h" |
35 | 36 | ||
36 | struct nv84_fence_chan { | 37 | u64 |
37 | struct nouveau_fence_chan base; | 38 | nv84_fence_crtc(struct nouveau_channel *chan, int crtc) |
38 | }; | 39 | { |
39 | 40 | struct nv84_fence_chan *fctx = chan->fence; | |
40 | struct nv84_fence_priv { | 41 | return fctx->dispc_vma[crtc].offset; |
41 | struct nouveau_fence_priv base; | 42 | } |
42 | struct nouveau_gpuobj *mem; | ||
43 | }; | ||
44 | 43 | ||
45 | static int | 44 | static int |
46 | nv84_fence_emit(struct nouveau_fence *fence) | 45 | nv84_fence_emit32(struct nouveau_channel *chan, u64 virtual, u32 sequence) |
47 | { | 46 | { |
48 | struct nouveau_channel *chan = fence->channel; | 47 | int ret = RING_SPACE(chan, 8); |
49 | struct nouveau_fifo_chan *fifo = (void *)chan->object; | ||
50 | int ret = RING_SPACE(chan, 7); | ||
51 | if (ret == 0) { | 48 | if (ret == 0) { |
52 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); | 49 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); |
53 | OUT_RING (chan, NvSema); | 50 | OUT_RING (chan, chan->vram); |
54 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 51 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 5); |
55 | OUT_RING (chan, upper_32_bits(fifo->chid * 16)); | 52 | OUT_RING (chan, upper_32_bits(virtual)); |
56 | OUT_RING (chan, lower_32_bits(fifo->chid * 16)); | 53 | OUT_RING (chan, lower_32_bits(virtual)); |
57 | OUT_RING (chan, fence->sequence); | 54 | OUT_RING (chan, sequence); |
58 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); | 55 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); |
56 | OUT_RING (chan, 0x00000000); | ||
59 | FIRE_RING (chan); | 57 | FIRE_RING (chan); |
60 | } | 58 | } |
61 | return ret; | 59 | return ret; |
62 | } | 60 | } |
63 | 61 | ||
64 | |||
65 | static int | 62 | static int |
66 | nv84_fence_sync(struct nouveau_fence *fence, | 63 | nv84_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence) |
67 | struct nouveau_channel *prev, struct nouveau_channel *chan) | ||
68 | { | 64 | { |
69 | struct nouveau_fifo_chan *fifo = (void *)prev->object; | ||
70 | int ret = RING_SPACE(chan, 7); | 65 | int ret = RING_SPACE(chan, 7); |
71 | if (ret == 0) { | 66 | if (ret == 0) { |
72 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); | 67 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); |
73 | OUT_RING (chan, NvSema); | 68 | OUT_RING (chan, chan->vram); |
74 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 69 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); |
75 | OUT_RING (chan, upper_32_bits(fifo->chid * 16)); | 70 | OUT_RING (chan, upper_32_bits(virtual)); |
76 | OUT_RING (chan, lower_32_bits(fifo->chid * 16)); | 71 | OUT_RING (chan, lower_32_bits(virtual)); |
77 | OUT_RING (chan, fence->sequence); | 72 | OUT_RING (chan, sequence); |
78 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL); | 73 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL); |
79 | FIRE_RING (chan); | 74 | FIRE_RING (chan); |
80 | } | 75 | } |
81 | return ret; | 76 | return ret; |
82 | } | 77 | } |
83 | 78 | ||
79 | static int | ||
80 | nv84_fence_emit(struct nouveau_fence *fence) | ||
81 | { | ||
82 | struct nouveau_channel *chan = fence->channel; | ||
83 | struct nv84_fence_chan *fctx = chan->fence; | ||
84 | struct nouveau_fifo_chan *fifo = (void *)chan->object; | ||
85 | u64 addr = fifo->chid * 16; | ||
86 | |||
87 | if (fence->sysmem) | ||
88 | addr += fctx->vma_gart.offset; | ||
89 | else | ||
90 | addr += fctx->vma.offset; | ||
91 | |||
92 | return fctx->base.emit32(chan, addr, fence->sequence); | ||
93 | } | ||
94 | |||
95 | static int | ||
96 | nv84_fence_sync(struct nouveau_fence *fence, | ||
97 | struct nouveau_channel *prev, struct nouveau_channel *chan) | ||
98 | { | ||
99 | struct nv84_fence_chan *fctx = chan->fence; | ||
100 | struct nouveau_fifo_chan *fifo = (void *)prev->object; | ||
101 | u64 addr = fifo->chid * 16; | ||
102 | |||
103 | if (fence->sysmem) | ||
104 | addr += fctx->vma_gart.offset; | ||
105 | else | ||
106 | addr += fctx->vma.offset; | ||
107 | |||
108 | return fctx->base.sync32(chan, addr, fence->sequence); | ||
109 | } | ||
110 | |||
84 | static u32 | 111 | static u32 |
85 | nv84_fence_read(struct nouveau_channel *chan) | 112 | nv84_fence_read(struct nouveau_channel *chan) |
86 | { | 113 | { |
87 | struct nouveau_fifo_chan *fifo = (void *)chan->object; | 114 | struct nouveau_fifo_chan *fifo = (void *)chan->object; |
88 | struct nv84_fence_priv *priv = chan->drm->fence; | 115 | struct nv84_fence_priv *priv = chan->drm->fence; |
89 | return nv_ro32(priv->mem, fifo->chid * 16); | 116 | return nouveau_bo_rd32(priv->bo, fifo->chid * 16/4); |
90 | } | 117 | } |
91 | 118 | ||
92 | static void | 119 | static void |
93 | nv84_fence_context_del(struct nouveau_channel *chan) | 120 | nv84_fence_context_del(struct nouveau_channel *chan) |
94 | { | 121 | { |
122 | struct drm_device *dev = chan->drm->dev; | ||
123 | struct nv84_fence_priv *priv = chan->drm->fence; | ||
95 | struct nv84_fence_chan *fctx = chan->fence; | 124 | struct nv84_fence_chan *fctx = chan->fence; |
125 | int i; | ||
126 | |||
127 | for (i = 0; i < dev->mode_config.num_crtc; i++) { | ||
128 | struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i); | ||
129 | nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]); | ||
130 | } | ||
131 | |||
132 | nouveau_bo_vma_del(priv->bo, &fctx->vma_gart); | ||
133 | nouveau_bo_vma_del(priv->bo, &fctx->vma); | ||
96 | nouveau_fence_context_del(&fctx->base); | 134 | nouveau_fence_context_del(&fctx->base); |
97 | chan->fence = NULL; | 135 | chan->fence = NULL; |
98 | kfree(fctx); | 136 | kfree(fctx); |
99 | } | 137 | } |
100 | 138 | ||
101 | static int | 139 | int |
102 | nv84_fence_context_new(struct nouveau_channel *chan) | 140 | nv84_fence_context_new(struct nouveau_channel *chan) |
103 | { | 141 | { |
104 | struct drm_device *dev = chan->drm->dev; | ||
105 | struct nouveau_fifo_chan *fifo = (void *)chan->object; | 142 | struct nouveau_fifo_chan *fifo = (void *)chan->object; |
143 | struct nouveau_client *client = nouveau_client(fifo); | ||
106 | struct nv84_fence_priv *priv = chan->drm->fence; | 144 | struct nv84_fence_priv *priv = chan->drm->fence; |
107 | struct nv84_fence_chan *fctx; | 145 | struct nv84_fence_chan *fctx; |
108 | struct nouveau_object *object; | ||
109 | int ret, i; | 146 | int ret, i; |
110 | 147 | ||
111 | fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); | 148 | fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); |
@@ -113,44 +150,74 @@ nv84_fence_context_new(struct nouveau_channel *chan) | |||
113 | return -ENOMEM; | 150 | return -ENOMEM; |
114 | 151 | ||
115 | nouveau_fence_context_new(&fctx->base); | 152 | nouveau_fence_context_new(&fctx->base); |
153 | fctx->base.emit = nv84_fence_emit; | ||
154 | fctx->base.sync = nv84_fence_sync; | ||
155 | fctx->base.read = nv84_fence_read; | ||
156 | fctx->base.emit32 = nv84_fence_emit32; | ||
157 | fctx->base.sync32 = nv84_fence_sync32; | ||
116 | 158 | ||
117 | ret = nouveau_object_new(nv_object(chan->cli), chan->handle, | 159 | ret = nouveau_bo_vma_add(priv->bo, client->vm, &fctx->vma); |
118 | NvSema, 0x0002, | 160 | if (ret == 0) { |
119 | &(struct nv_dma_class) { | 161 | ret = nouveau_bo_vma_add(priv->bo_gart, client->vm, |
120 | .flags = NV_DMA_TARGET_VRAM | | 162 | &fctx->vma_gart); |
121 | NV_DMA_ACCESS_RDWR, | 163 | } |
122 | .start = priv->mem->addr, | ||
123 | .limit = priv->mem->addr + | ||
124 | priv->mem->size - 1, | ||
125 | }, sizeof(struct nv_dma_class), | ||
126 | &object); | ||
127 | |||
128 | /* dma objects for display sync channel semaphore blocks */ | ||
129 | for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) { | ||
130 | struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i); | ||
131 | 164 | ||
132 | ret = nouveau_object_new(nv_object(chan->cli), chan->handle, | 165 | /* map display semaphore buffers into channel's vm */ |
133 | NvEvoSema0 + i, 0x003d, | 166 | for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) { |
134 | &(struct nv_dma_class) { | 167 | struct nouveau_bo *bo = nv50_display_crtc_sema(chan->drm->dev, i); |
135 | .flags = NV_DMA_TARGET_VRAM | | 168 | ret = nouveau_bo_vma_add(bo, client->vm, &fctx->dispc_vma[i]); |
136 | NV_DMA_ACCESS_RDWR, | ||
137 | .start = bo->bo.offset, | ||
138 | .limit = bo->bo.offset + 0xfff, | ||
139 | }, sizeof(struct nv_dma_class), | ||
140 | &object); | ||
141 | } | 169 | } |
142 | 170 | ||
171 | nouveau_bo_wr32(priv->bo, fifo->chid * 16/4, 0x00000000); | ||
172 | |||
143 | if (ret) | 173 | if (ret) |
144 | nv84_fence_context_del(chan); | 174 | nv84_fence_context_del(chan); |
145 | nv_wo32(priv->mem, fifo->chid * 16, 0x00000000); | ||
146 | return ret; | 175 | return ret; |
147 | } | 176 | } |
148 | 177 | ||
178 | static bool | ||
179 | nv84_fence_suspend(struct nouveau_drm *drm) | ||
180 | { | ||
181 | struct nouveau_fifo *pfifo = nouveau_fifo(drm->device); | ||
182 | struct nv84_fence_priv *priv = drm->fence; | ||
183 | int i; | ||
184 | |||
185 | priv->suspend = vmalloc((pfifo->max + 1) * sizeof(u32)); | ||
186 | if (priv->suspend) { | ||
187 | for (i = 0; i <= pfifo->max; i++) | ||
188 | priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4); | ||
189 | } | ||
190 | |||
191 | return priv->suspend != NULL; | ||
192 | } | ||
193 | |||
194 | static void | ||
195 | nv84_fence_resume(struct nouveau_drm *drm) | ||
196 | { | ||
197 | struct nouveau_fifo *pfifo = nouveau_fifo(drm->device); | ||
198 | struct nv84_fence_priv *priv = drm->fence; | ||
199 | int i; | ||
200 | |||
201 | if (priv->suspend) { | ||
202 | for (i = 0; i <= pfifo->max; i++) | ||
203 | nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]); | ||
204 | vfree(priv->suspend); | ||
205 | priv->suspend = NULL; | ||
206 | } | ||
207 | } | ||
208 | |||
149 | static void | 209 | static void |
150 | nv84_fence_destroy(struct nouveau_drm *drm) | 210 | nv84_fence_destroy(struct nouveau_drm *drm) |
151 | { | 211 | { |
152 | struct nv84_fence_priv *priv = drm->fence; | 212 | struct nv84_fence_priv *priv = drm->fence; |
153 | nouveau_gpuobj_ref(NULL, &priv->mem); | 213 | nouveau_bo_unmap(priv->bo_gart); |
214 | if (priv->bo_gart) | ||
215 | nouveau_bo_unpin(priv->bo_gart); | ||
216 | nouveau_bo_ref(NULL, &priv->bo_gart); | ||
217 | nouveau_bo_unmap(priv->bo); | ||
218 | if (priv->bo) | ||
219 | nouveau_bo_unpin(priv->bo); | ||
220 | nouveau_bo_ref(NULL, &priv->bo); | ||
154 | drm->fence = NULL; | 221 | drm->fence = NULL; |
155 | kfree(priv); | 222 | kfree(priv); |
156 | } | 223 | } |
@@ -160,7 +227,6 @@ nv84_fence_create(struct nouveau_drm *drm) | |||
160 | { | 227 | { |
161 | struct nouveau_fifo *pfifo = nouveau_fifo(drm->device); | 228 | struct nouveau_fifo *pfifo = nouveau_fifo(drm->device); |
162 | struct nv84_fence_priv *priv; | 229 | struct nv84_fence_priv *priv; |
163 | u32 chan = pfifo->max + 1; | ||
164 | int ret; | 230 | int ret; |
165 | 231 | ||
166 | priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL); | 232 | priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL); |
@@ -168,14 +234,42 @@ nv84_fence_create(struct nouveau_drm *drm) | |||
168 | return -ENOMEM; | 234 | return -ENOMEM; |
169 | 235 | ||
170 | priv->base.dtor = nv84_fence_destroy; | 236 | priv->base.dtor = nv84_fence_destroy; |
237 | priv->base.suspend = nv84_fence_suspend; | ||
238 | priv->base.resume = nv84_fence_resume; | ||
171 | priv->base.context_new = nv84_fence_context_new; | 239 | priv->base.context_new = nv84_fence_context_new; |
172 | priv->base.context_del = nv84_fence_context_del; | 240 | priv->base.context_del = nv84_fence_context_del; |
173 | priv->base.emit = nv84_fence_emit; | ||
174 | priv->base.sync = nv84_fence_sync; | ||
175 | priv->base.read = nv84_fence_read; | ||
176 | 241 | ||
177 | ret = nouveau_gpuobj_new(drm->device, NULL, chan * 16, 0x1000, 0, | 242 | init_waitqueue_head(&priv->base.waiting); |
178 | &priv->mem); | 243 | priv->base.uevent = true; |
244 | |||
245 | ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0, | ||
246 | TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo); | ||
247 | if (ret == 0) { | ||
248 | ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); | ||
249 | if (ret == 0) { | ||
250 | ret = nouveau_bo_map(priv->bo); | ||
251 | if (ret) | ||
252 | nouveau_bo_unpin(priv->bo); | ||
253 | } | ||
254 | if (ret) | ||
255 | nouveau_bo_ref(NULL, &priv->bo); | ||
256 | } | ||
257 | |||
258 | if (ret == 0) | ||
259 | ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0, | ||
260 | TTM_PL_FLAG_TT, 0, 0, NULL, | ||
261 | &priv->bo_gart); | ||
262 | if (ret == 0) { | ||
263 | ret = nouveau_bo_pin(priv->bo_gart, TTM_PL_FLAG_TT); | ||
264 | if (ret == 0) { | ||
265 | ret = nouveau_bo_map(priv->bo_gart); | ||
266 | if (ret) | ||
267 | nouveau_bo_unpin(priv->bo_gart); | ||
268 | } | ||
269 | if (ret) | ||
270 | nouveau_bo_ref(NULL, &priv->bo_gart); | ||
271 | } | ||
272 | |||
179 | if (ret) | 273 | if (ret) |
180 | nv84_fence_destroy(drm); | 274 | nv84_fence_destroy(drm); |
181 | return ret; | 275 | return ret; |
diff --git a/drivers/gpu/drm/nouveau/nvc0_fence.c b/drivers/gpu/drm/nouveau/nvc0_fence.c index 2a56b1b551cb..9566267fbc42 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fence.c +++ b/drivers/gpu/drm/nouveau/nvc0_fence.c | |||
@@ -34,203 +34,57 @@ | |||
34 | 34 | ||
35 | #include "nv50_display.h" | 35 | #include "nv50_display.h" |
36 | 36 | ||
37 | struct nvc0_fence_priv { | ||
38 | struct nouveau_fence_priv base; | ||
39 | struct nouveau_bo *bo; | ||
40 | u32 *suspend; | ||
41 | }; | ||
42 | |||
43 | struct nvc0_fence_chan { | ||
44 | struct nouveau_fence_chan base; | ||
45 | struct nouveau_vma vma; | ||
46 | struct nouveau_vma dispc_vma[4]; | ||
47 | }; | ||
48 | |||
49 | u64 | ||
50 | nvc0_fence_crtc(struct nouveau_channel *chan, int crtc) | ||
51 | { | ||
52 | struct nvc0_fence_chan *fctx = chan->fence; | ||
53 | return fctx->dispc_vma[crtc].offset; | ||
54 | } | ||
55 | |||
56 | static int | 37 | static int |
57 | nvc0_fence_emit(struct nouveau_fence *fence) | 38 | nvc0_fence_emit32(struct nouveau_channel *chan, u64 virtual, u32 sequence) |
58 | { | 39 | { |
59 | struct nouveau_channel *chan = fence->channel; | 40 | int ret = RING_SPACE(chan, 6); |
60 | struct nvc0_fence_chan *fctx = chan->fence; | ||
61 | struct nouveau_fifo_chan *fifo = (void *)chan->object; | ||
62 | u64 addr = fctx->vma.offset + fifo->chid * 16; | ||
63 | int ret; | ||
64 | |||
65 | ret = RING_SPACE(chan, 5); | ||
66 | if (ret == 0) { | 41 | if (ret == 0) { |
67 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 42 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 5); |
68 | OUT_RING (chan, upper_32_bits(addr)); | 43 | OUT_RING (chan, upper_32_bits(virtual)); |
69 | OUT_RING (chan, lower_32_bits(addr)); | 44 | OUT_RING (chan, lower_32_bits(virtual)); |
70 | OUT_RING (chan, fence->sequence); | 45 | OUT_RING (chan, sequence); |
71 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); | 46 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); |
47 | OUT_RING (chan, 0x00000000); | ||
72 | FIRE_RING (chan); | 48 | FIRE_RING (chan); |
73 | } | 49 | } |
74 | |||
75 | return ret; | 50 | return ret; |
76 | } | 51 | } |
77 | 52 | ||
78 | static int | 53 | static int |
79 | nvc0_fence_sync(struct nouveau_fence *fence, | 54 | nvc0_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence) |
80 | struct nouveau_channel *prev, struct nouveau_channel *chan) | ||
81 | { | 55 | { |
82 | struct nvc0_fence_chan *fctx = chan->fence; | 56 | int ret = RING_SPACE(chan, 5); |
83 | struct nouveau_fifo_chan *fifo = (void *)prev->object; | ||
84 | u64 addr = fctx->vma.offset + fifo->chid * 16; | ||
85 | int ret; | ||
86 | |||
87 | ret = RING_SPACE(chan, 5); | ||
88 | if (ret == 0) { | 57 | if (ret == 0) { |
89 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 58 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); |
90 | OUT_RING (chan, upper_32_bits(addr)); | 59 | OUT_RING (chan, upper_32_bits(virtual)); |
91 | OUT_RING (chan, lower_32_bits(addr)); | 60 | OUT_RING (chan, lower_32_bits(virtual)); |
92 | OUT_RING (chan, fence->sequence); | 61 | OUT_RING (chan, sequence); |
93 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL | | 62 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL | |
94 | NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD); | 63 | NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD); |
95 | FIRE_RING (chan); | 64 | FIRE_RING (chan); |
96 | } | 65 | } |
97 | |||
98 | return ret; | 66 | return ret; |
99 | } | 67 | } |
100 | 68 | ||
101 | static u32 | ||
102 | nvc0_fence_read(struct nouveau_channel *chan) | ||
103 | { | ||
104 | struct nouveau_fifo_chan *fifo = (void *)chan->object; | ||
105 | struct nvc0_fence_priv *priv = chan->drm->fence; | ||
106 | return nouveau_bo_rd32(priv->bo, fifo->chid * 16/4); | ||
107 | } | ||
108 | |||
109 | static void | ||
110 | nvc0_fence_context_del(struct nouveau_channel *chan) | ||
111 | { | ||
112 | struct drm_device *dev = chan->drm->dev; | ||
113 | struct nvc0_fence_priv *priv = chan->drm->fence; | ||
114 | struct nvc0_fence_chan *fctx = chan->fence; | ||
115 | int i; | ||
116 | |||
117 | for (i = 0; i < dev->mode_config.num_crtc; i++) { | ||
118 | struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i); | ||
119 | nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]); | ||
120 | } | ||
121 | |||
122 | nouveau_bo_vma_del(priv->bo, &fctx->vma); | ||
123 | nouveau_fence_context_del(&fctx->base); | ||
124 | chan->fence = NULL; | ||
125 | kfree(fctx); | ||
126 | } | ||
127 | |||
128 | static int | 69 | static int |
129 | nvc0_fence_context_new(struct nouveau_channel *chan) | 70 | nvc0_fence_context_new(struct nouveau_channel *chan) |
130 | { | 71 | { |
131 | struct nouveau_fifo_chan *fifo = (void *)chan->object; | 72 | int ret = nv84_fence_context_new(chan); |
132 | struct nouveau_client *client = nouveau_client(fifo); | 73 | if (ret == 0) { |
133 | struct nvc0_fence_priv *priv = chan->drm->fence; | 74 | struct nv84_fence_chan *fctx = chan->fence; |
134 | struct nvc0_fence_chan *fctx; | 75 | fctx->base.emit32 = nvc0_fence_emit32; |
135 | int ret, i; | 76 | fctx->base.sync32 = nvc0_fence_sync32; |
136 | |||
137 | fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); | ||
138 | if (!fctx) | ||
139 | return -ENOMEM; | ||
140 | |||
141 | nouveau_fence_context_new(&fctx->base); | ||
142 | |||
143 | ret = nouveau_bo_vma_add(priv->bo, client->vm, &fctx->vma); | ||
144 | if (ret) | ||
145 | nvc0_fence_context_del(chan); | ||
146 | |||
147 | /* map display semaphore buffers into channel's vm */ | ||
148 | for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) { | ||
149 | struct nouveau_bo *bo = nv50_display_crtc_sema(chan->drm->dev, i); | ||
150 | ret = nouveau_bo_vma_add(bo, client->vm, &fctx->dispc_vma[i]); | ||
151 | } | 77 | } |
152 | |||
153 | nouveau_bo_wr32(priv->bo, fifo->chid * 16/4, 0x00000000); | ||
154 | return ret; | 78 | return ret; |
155 | } | 79 | } |
156 | 80 | ||
157 | static bool | ||
158 | nvc0_fence_suspend(struct nouveau_drm *drm) | ||
159 | { | ||
160 | struct nouveau_fifo *pfifo = nouveau_fifo(drm->device); | ||
161 | struct nvc0_fence_priv *priv = drm->fence; | ||
162 | int i; | ||
163 | |||
164 | priv->suspend = vmalloc((pfifo->max + 1) * sizeof(u32)); | ||
165 | if (priv->suspend) { | ||
166 | for (i = 0; i <= pfifo->max; i++) | ||
167 | priv->suspend[i] = nouveau_bo_rd32(priv->bo, i); | ||
168 | } | ||
169 | |||
170 | return priv->suspend != NULL; | ||
171 | } | ||
172 | |||
173 | static void | ||
174 | nvc0_fence_resume(struct nouveau_drm *drm) | ||
175 | { | ||
176 | struct nouveau_fifo *pfifo = nouveau_fifo(drm->device); | ||
177 | struct nvc0_fence_priv *priv = drm->fence; | ||
178 | int i; | ||
179 | |||
180 | if (priv->suspend) { | ||
181 | for (i = 0; i <= pfifo->max; i++) | ||
182 | nouveau_bo_wr32(priv->bo, i, priv->suspend[i]); | ||
183 | vfree(priv->suspend); | ||
184 | priv->suspend = NULL; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | static void | ||
189 | nvc0_fence_destroy(struct nouveau_drm *drm) | ||
190 | { | ||
191 | struct nvc0_fence_priv *priv = drm->fence; | ||
192 | nouveau_bo_unmap(priv->bo); | ||
193 | if (priv->bo) | ||
194 | nouveau_bo_unpin(priv->bo); | ||
195 | nouveau_bo_ref(NULL, &priv->bo); | ||
196 | drm->fence = NULL; | ||
197 | kfree(priv); | ||
198 | } | ||
199 | |||
200 | int | 81 | int |
201 | nvc0_fence_create(struct nouveau_drm *drm) | 82 | nvc0_fence_create(struct nouveau_drm *drm) |
202 | { | 83 | { |
203 | struct nouveau_fifo *pfifo = nouveau_fifo(drm->device); | 84 | int ret = nv84_fence_create(drm); |
204 | struct nvc0_fence_priv *priv; | ||
205 | int ret; | ||
206 | |||
207 | priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
208 | if (!priv) | ||
209 | return -ENOMEM; | ||
210 | |||
211 | priv->base.dtor = nvc0_fence_destroy; | ||
212 | priv->base.suspend = nvc0_fence_suspend; | ||
213 | priv->base.resume = nvc0_fence_resume; | ||
214 | priv->base.context_new = nvc0_fence_context_new; | ||
215 | priv->base.context_del = nvc0_fence_context_del; | ||
216 | priv->base.emit = nvc0_fence_emit; | ||
217 | priv->base.sync = nvc0_fence_sync; | ||
218 | priv->base.read = nvc0_fence_read; | ||
219 | |||
220 | ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0, | ||
221 | TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo); | ||
222 | if (ret == 0) { | 85 | if (ret == 0) { |
223 | ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); | 86 | struct nv84_fence_priv *priv = drm->fence; |
224 | if (ret == 0) { | 87 | priv->base.context_new = nvc0_fence_context_new; |
225 | ret = nouveau_bo_map(priv->bo); | ||
226 | if (ret) | ||
227 | nouveau_bo_unpin(priv->bo); | ||
228 | } | ||
229 | if (ret) | ||
230 | nouveau_bo_ref(NULL, &priv->bo); | ||
231 | } | 88 | } |
232 | |||
233 | if (ret) | ||
234 | nvc0_fence_destroy(drm); | ||
235 | return ret; | 89 | return ret; |
236 | } | 90 | } |