Commit | Line | Data |
---|---|---|
ebb945a9 BS |
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 | */ | |
f84aff4e | 24 | #include "nv50.h" |
ebb945a9 | 25 | |
ebb945a9 | 26 | #include <core/handle.h> |
ebb945a9 | 27 | #include <engine/disp.h> |
8f0649b5 | 28 | #include <engine/fifo/chan.h> |
f84aff4e | 29 | #include <subdev/bar.h> |
ebb945a9 | 30 | |
f84aff4e | 31 | #include <nvif/event.h> |
f58ddf95 | 32 | #include <nvif/ioctl.h> |
ebb945a9 | 33 | |
ebb945a9 BS |
34 | /******************************************************************************* |
35 | * software context | |
36 | ******************************************************************************/ | |
37 | ||
1d7c71a3 | 38 | static int |
07b9e6cc | 39 | nv50_sw_chan_vblsem_release(struct nvkm_notify *notify) |
1d7c71a3 | 40 | { |
8700287b | 41 | struct nv50_sw_chan *chan = |
79ca2770 | 42 | container_of(notify, typeof(*chan), vblank.notify[notify->index]); |
07b9e6cc | 43 | struct nvkm_sw *sw = chan->base.sw; |
01d64afc BS |
44 | struct nvkm_device *device = sw->engine.subdev.device; |
45 | struct nvkm_bar *bar = device->bar; | |
1d7c71a3 | 46 | |
07b9e6cc | 47 | nvkm_wr32(device, 0x001704, chan->base.fifo->inst->addr >> 12); |
01d64afc | 48 | nvkm_wr32(device, 0x001710, 0x80000000 | chan->vblank.ctxdma); |
1d7c71a3 BS |
49 | bar->flush(bar); |
50 | ||
226dcefe | 51 | if (nv_device(sw)->chipset == 0x50) { |
01d64afc BS |
52 | nvkm_wr32(device, 0x001570, chan->vblank.offset); |
53 | nvkm_wr32(device, 0x001574, chan->vblank.value); | |
1d7c71a3 | 54 | } else { |
01d64afc BS |
55 | nvkm_wr32(device, 0x060010, chan->vblank.offset); |
56 | nvkm_wr32(device, 0x060014, chan->vblank.value); | |
1d7c71a3 BS |
57 | } |
58 | ||
79ca2770 | 59 | return NVKM_NOTIFY_DROP; |
1d7c71a3 BS |
60 | } |
61 | ||
61570911 BS |
62 | static bool |
63 | nv50_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) | |
64 | { | |
65 | struct nv50_sw_chan *chan = nv50_sw_chan(base); | |
07b9e6cc | 66 | struct nvkm_engine *engine = chan->base.object.engine; |
2a7909c0 | 67 | struct nvkm_device *device = engine->subdev.device; |
61570911 BS |
68 | switch (mthd) { |
69 | case 0x018c: chan->vblank.ctxdma = data; return true; | |
70 | case 0x0400: chan->vblank.offset = data; return true; | |
71 | case 0x0404: chan->vblank.value = data; return true; | |
72 | case 0x0408: | |
2a7909c0 | 73 | if (data < device->disp->vblank.index_nr) { |
61570911 BS |
74 | nvkm_notify_get(&chan->vblank.notify[data]); |
75 | return true; | |
76 | } | |
77 | break; | |
78 | default: | |
79 | break; | |
80 | } | |
81 | return false; | |
82 | } | |
83 | ||
07b9e6cc BS |
84 | void * |
85 | nv50_sw_chan_dtor(struct nvkm_sw_chan *base) | |
51cb4b39 | 86 | { |
07b9e6cc | 87 | struct nv50_sw_chan *chan = nv50_sw_chan(base); |
51cb4b39 | 88 | int i; |
79ca2770 BS |
89 | for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++) |
90 | nvkm_notify_fini(&chan->vblank.notify[i]); | |
07b9e6cc | 91 | return chan; |
51cb4b39 BS |
92 | } |
93 | ||
07b9e6cc BS |
94 | static const struct nvkm_sw_chan_func |
95 | nv50_sw_chan = { | |
96 | .dtor = nv50_sw_chan_dtor, | |
97 | .mthd = nv50_sw_chan_mthd, | |
98 | }; | |
99 | ||
100 | static int | |
101 | nv50_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch, | |
102 | const struct nvkm_oclass *oclass, struct nvkm_object **pobject) | |
ebb945a9 | 103 | { |
07b9e6cc | 104 | struct nvkm_disp *disp = sw->engine.subdev.device->disp; |
8700287b | 105 | struct nv50_sw_chan *chan; |
51cb4b39 | 106 | int ret, i; |
ebb945a9 | 107 | |
07b9e6cc BS |
108 | if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) |
109 | return -ENOMEM; | |
110 | *pobject = &chan->base.object; | |
111 | ||
112 | ret = nvkm_sw_chan_ctor(&nv50_sw_chan, sw, fifoch, oclass, &chan->base); | |
ebb945a9 BS |
113 | if (ret) |
114 | return ret; | |
115 | ||
fd166a18 | 116 | for (i = 0; disp && i < disp->vblank.index_nr; i++) { |
07b9e6cc BS |
117 | ret = nvkm_notify_init(NULL, &disp->vblank, |
118 | nv50_sw_chan_vblsem_release, false, | |
79ca2770 BS |
119 | &(struct nvif_notify_head_req_v0) { |
120 | .head = i, | |
121 | }, | |
122 | sizeof(struct nvif_notify_head_req_v0), | |
123 | sizeof(struct nvif_notify_head_rep_v0), | |
124 | &chan->vblank.notify[i]); | |
51cb4b39 BS |
125 | if (ret) |
126 | return ret; | |
127 | } | |
128 | ||
ebb945a9 BS |
129 | return 0; |
130 | } | |
131 | ||
ebb945a9 BS |
132 | /******************************************************************************* |
133 | * software engine/subdev functions | |
134 | ******************************************************************************/ | |
135 | ||
7589563e | 136 | int |
f84aff4e BS |
137 | nv50_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, |
138 | struct nvkm_oclass *oclass, void *data, u32 size, | |
139 | struct nvkm_object **pobject) | |
ebb945a9 | 140 | { |
8700287b | 141 | struct nv50_sw_oclass *pclass = (void *)oclass; |
226dcefe | 142 | struct nvkm_sw *sw; |
ebb945a9 BS |
143 | int ret; |
144 | ||
226dcefe BS |
145 | ret = nvkm_sw_create(parent, engine, oclass, &sw); |
146 | *pobject = nv_object(sw); | |
ebb945a9 BS |
147 | if (ret) |
148 | return ret; | |
149 | ||
07b9e6cc | 150 | sw->func = pclass->func; |
226dcefe | 151 | nv_subdev(sw)->intr = nv04_sw_intr; |
ebb945a9 BS |
152 | return 0; |
153 | } | |
154 | ||
07b9e6cc BS |
155 | static const struct nvkm_sw_func |
156 | nv50_sw_func = { | |
157 | .chan_new = nv50_sw_chan_new, | |
158 | .sclass = { | |
159 | { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV50 } }, | |
160 | {} | |
161 | } | |
162 | }; | |
163 | ||
f84aff4e | 164 | struct nvkm_oclass * |
8700287b | 165 | nv50_sw_oclass = &(struct nv50_sw_oclass) { |
c46c3ddf | 166 | .base.handle = NV_ENGINE(SW, 0x50), |
f84aff4e | 167 | .base.ofuncs = &(struct nvkm_ofuncs) { |
8700287b | 168 | .ctor = nv50_sw_ctor, |
f84aff4e BS |
169 | .dtor = _nvkm_sw_dtor, |
170 | .init = _nvkm_sw_init, | |
171 | .fini = _nvkm_sw_fini, | |
ebb945a9 | 172 | }, |
07b9e6cc | 173 | .func = &nv50_sw_func, |
c46c3ddf | 174 | }.base; |