OSDN Git Service

drm/nouveau/subdev: implement support for new-style nvkm_subdev
[uclinux-h8/linux.git] / drivers / gpu / drm / nouveau / nvkm / core / subdev.c
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 #include <core/subdev.h>
25 #include <core/device.h>
26 #include <core/option.h>
27
28 static struct lock_class_key nvkm_subdev_lock_class[NVDEV_SUBDEV_NR];
29
30 const char *
31 nvkm_subdev_name[64] = {
32         [NVDEV_SUBDEV_BAR    ] = "bar",
33         [NVDEV_SUBDEV_VBIOS  ] = "bios",
34         [NVDEV_SUBDEV_BUS    ] = "bus",
35         [NVDEV_SUBDEV_CLK    ] = "clk",
36         [NVDEV_SUBDEV_DEVINIT] = "devinit",
37         [NVDEV_SUBDEV_FB     ] = "fb",
38         [NVDEV_SUBDEV_FUSE   ] = "fuse",
39         [NVDEV_SUBDEV_GPIO   ] = "gpio",
40         [NVDEV_SUBDEV_I2C    ] = "i2c",
41         [NVDEV_SUBDEV_IBUS   ] = "priv",
42         [NVDEV_SUBDEV_INSTMEM] = "imem",
43         [NVDEV_SUBDEV_LTC    ] = "ltc",
44         [NVDEV_SUBDEV_MC     ] = "mc",
45         [NVDEV_SUBDEV_MMU    ] = "mmu",
46         [NVDEV_SUBDEV_MXM    ] = "mxm",
47         [NVDEV_SUBDEV_PMU    ] = "pmu",
48         [NVDEV_SUBDEV_THERM  ] = "therm",
49         [NVDEV_SUBDEV_TIMER  ] = "tmr",
50         [NVDEV_SUBDEV_VOLT   ] = "volt",
51         [NVDEV_ENGINE_BSP    ] = "bsp",
52         [NVDEV_ENGINE_CE0    ] = "ce0",
53         [NVDEV_ENGINE_CE1    ] = "ce1",
54         [NVDEV_ENGINE_CE2    ] = "ce2",
55         [NVDEV_ENGINE_CIPHER ] = "cipher",
56         [NVDEV_ENGINE_DISP   ] = "disp",
57         [NVDEV_ENGINE_DMAOBJ ] = "dma",
58         [NVDEV_ENGINE_FIFO   ] = "fifo",
59         [NVDEV_ENGINE_GR     ] = "gr",
60         [NVDEV_ENGINE_IFB    ] = "ifb",
61         [NVDEV_ENGINE_ME     ] = "me",
62         [NVDEV_ENGINE_MPEG   ] = "mpeg",
63         [NVDEV_ENGINE_MSENC  ] = "msenc",
64         [NVDEV_ENGINE_MSPDEC ] = "mspdec",
65         [NVDEV_ENGINE_MSPPP  ] = "msppp",
66         [NVDEV_ENGINE_MSVLD  ] = "msvld",
67         [NVDEV_ENGINE_PM     ] = "pm",
68         [NVDEV_ENGINE_SEC    ] = "sec",
69         [NVDEV_ENGINE_SW     ] = "sw",
70         [NVDEV_ENGINE_VIC    ] = "vic",
71         [NVDEV_ENGINE_VP     ] = "vp",
72 };
73
74 void
75 nvkm_subdev_intr(struct nvkm_subdev *subdev)
76 {
77         if (subdev->func->intr)
78                 subdev->func->intr(subdev);
79 }
80
81 int
82 nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend)
83 {
84         struct nvkm_device *device = subdev->device;
85         const char *action = suspend ? "suspend" : "fini";
86         u32 pmc_enable = subdev->pmc_enable;
87         s64 time;
88
89         nvkm_trace(subdev, "%s running...\n", action);
90         time = ktime_to_us(ktime_get());
91
92         if (subdev->func->fini) {
93                 int ret = subdev->func->fini(subdev, suspend);
94                 if (ret) {
95                         nvkm_error(subdev, "%s failed, %d\n", action, ret);
96                         if (suspend)
97                                 return ret;
98                 }
99         }
100
101         if (pmc_enable) {
102                 nvkm_mask(device, 0x000200, pmc_enable, 0x00000000);
103                 nvkm_mask(device, 0x000200, pmc_enable, pmc_enable);
104                 nvkm_rd32(device, 0x000200);
105         }
106
107         time = ktime_to_us(ktime_get()) - time;
108         nvkm_trace(subdev, "%s completed in %lldus\n", action, time);
109         return 0;
110 }
111
112 int
113 nvkm_subdev_preinit(struct nvkm_subdev *subdev)
114 {
115         s64 time;
116
117         nvkm_trace(subdev, "preinit running...\n");
118         time = ktime_to_us(ktime_get());
119
120         if (subdev->func->preinit) {
121                 int ret = subdev->func->preinit(subdev);
122                 if (ret) {
123                         nvkm_error(subdev, "preinit failed, %d\n", ret);
124                         return ret;
125                 }
126         }
127
128         time = ktime_to_us(ktime_get()) - time;
129         nvkm_trace(subdev, "preinit completed in %lldus\n", time);
130         return 0;
131 }
132
133 int
134 nvkm_subdev_init(struct nvkm_subdev *subdev)
135 {
136         s64 time;
137         int ret;
138
139         nvkm_trace(subdev, "init running...\n");
140         time = ktime_to_us(ktime_get());
141
142         if (subdev->func->oneinit && !subdev->oneinit) {
143                 s64 time;
144                 nvkm_trace(subdev, "one-time init running...\n");
145                 time = ktime_to_us(ktime_get());
146                 ret = subdev->func->oneinit(subdev);
147                 if (ret) {
148                         nvkm_error(subdev, "one-time init failed, %d\n", ret);
149                         return ret;
150                 }
151
152                 subdev->oneinit = true;
153                 time = ktime_to_us(ktime_get()) - time;
154                 nvkm_trace(subdev, "one-time init completed in %lldus\n", time);
155         }
156
157         if (subdev->func->init) {
158                 ret = subdev->func->init(subdev);
159                 if (ret) {
160                         nvkm_error(subdev, "init failed, %d\n", ret);
161                         return ret;
162                 }
163         }
164
165         time = ktime_to_us(ktime_get()) - time;
166         nvkm_trace(subdev, "init completed in %lldus\n", time);
167         return 0;
168 }
169
170 void
171 nvkm_subdev_del(struct nvkm_subdev **psubdev)
172 {
173         struct nvkm_subdev *subdev = *psubdev;
174         s64 time;
175         if (subdev && !WARN_ON(!subdev->func)) {
176                 nvkm_trace(subdev, "destroy running...\n");
177                 time = ktime_to_us(ktime_get());
178                 if (subdev->func->dtor)
179                         *psubdev = subdev->func->dtor(subdev);
180                 time = ktime_to_us(ktime_get()) - time;
181                 nvkm_trace(subdev, "destroy completed in %lldus\n", time);
182                 kfree(*psubdev);
183                 *psubdev = NULL;
184         }
185 }
186
187 static const struct nvkm_object_func
188 nvkm_subdev_func = {
189 };
190
191 void
192 nvkm_subdev_ctor(const struct nvkm_subdev_func *func,
193                  struct nvkm_device *device, int index, u32 pmc_enable,
194                  struct nvkm_subdev *subdev)
195 {
196         const char *name = nvkm_subdev_name[index];
197         struct nvkm_oclass hack = {};
198         nvkm_object_ctor(&nvkm_subdev_func, &hack, &subdev->object);
199         subdev->func = func;
200         subdev->device = device;
201         subdev->index = index;
202         subdev->pmc_enable = pmc_enable;
203
204         __mutex_init(&subdev->mutex, name, &nvkm_subdev_lock_class[index]);
205         subdev->debug = nvkm_dbgopt(device->dbgopt, name);
206 }
207
208 struct nvkm_subdev *
209 nvkm_subdev(void *obj, int idx)
210 {
211         struct nvkm_object *object = nv_object(obj);
212         while (object && !nv_iclass(object, NV_SUBDEV_CLASS))
213                 object = object->parent;
214         if (object == NULL || !object->parent || nv_subidx(nv_subdev(object)) != idx)
215                 object = nv_device(obj)->subdev[idx];
216         return object ? nv_subdev(object) : NULL;
217 }
218
219 void
220 nvkm_subdev_reset(struct nvkm_object *obj)
221 {
222         struct nvkm_subdev *subdev = container_of(obj, typeof(*subdev), object);
223         nvkm_trace(subdev, "resetting...\n");
224         nvkm_object_fini(&subdev->object, false);
225         nvkm_trace(subdev, "reset\n");
226 }
227
228 int
229 nvkm_subdev_init_old(struct nvkm_subdev *subdev)
230 {
231         int ret = _nvkm_object_init(&subdev->object);
232         if (ret)
233                 return ret;
234
235         nvkm_subdev_reset(&subdev->object);
236         return 0;
237 }
238
239 int
240 _nvkm_subdev_init(struct nvkm_object *object)
241 {
242         struct nvkm_subdev *subdev = (void *)object;
243         return nvkm_subdev_init_old(subdev);
244 }
245
246 int
247 nvkm_subdev_fini_old(struct nvkm_subdev *subdev, bool suspend)
248 {
249         struct nvkm_device *device = subdev->device;
250
251         if (subdev->unit) {
252                 nvkm_mask(device, 0x000200, subdev->unit, 0x00000000);
253                 nvkm_mask(device, 0x000200, subdev->unit, subdev->unit);
254         }
255
256         return _nvkm_object_fini(&subdev->object, suspend);
257 }
258
259 int
260 _nvkm_subdev_fini(struct nvkm_object *object, bool suspend)
261 {
262         struct nvkm_subdev *subdev = (void *)object;
263         return nvkm_subdev_fini_old(subdev, suspend);
264 }
265
266 void
267 nvkm_subdev_destroy(struct nvkm_subdev *subdev)
268 {
269         int subidx = nv_hclass(subdev) & 0xff;
270         nv_device(subdev)->subdev[subidx] = NULL;
271         nvkm_object_destroy(&subdev->object);
272 }
273
274 void
275 _nvkm_subdev_dtor(struct nvkm_object *object)
276 {
277         nvkm_subdev_destroy(nv_subdev(object));
278 }
279
280 int
281 nvkm_subdev_create_(struct nvkm_object *parent, struct nvkm_object *engine,
282                     struct nvkm_oclass *oclass, u32 pclass,
283                     const char *subname, const char *sysname,
284                     int size, void **pobject)
285 {
286         const int subidx = oclass->handle & 0xff;
287         const char *name = nvkm_subdev_name[subidx];
288         struct nvkm_subdev *subdev;
289         int ret;
290
291         ret = nvkm_object_create_(parent, engine, oclass, pclass |
292                                   NV_SUBDEV_CLASS, size, pobject);
293         subdev = *pobject;
294         if (ret)
295                 return ret;
296
297         __mutex_init(&subdev->mutex, name, &nvkm_subdev_lock_class[subidx]);
298         subdev->index = subidx;
299
300         if (parent) {
301                 struct nvkm_device *device = nv_device(parent);
302                 subdev->debug = nvkm_dbgopt(device->dbgopt, name);
303                 subdev->device = device;
304         } else {
305                 subdev->device = nv_device(subdev);
306         }
307
308         return 0;
309 }