diff options
Diffstat (limited to 'drivers/gpu/host1x')
40 files changed, 1391 insertions, 6202 deletions
diff --git a/drivers/gpu/host1x/Kconfig b/drivers/gpu/host1x/Kconfig index ccfd42b23606..7d6bed222542 100644 --- a/drivers/gpu/host1x/Kconfig +++ b/drivers/gpu/host1x/Kconfig | |||
@@ -19,6 +19,4 @@ config TEGRA_HOST1X_FIREWALL | |||
19 | 19 | ||
20 | If unsure, choose Y. | 20 | If unsure, choose Y. |
21 | 21 | ||
22 | source "drivers/gpu/host1x/drm/Kconfig" | ||
23 | |||
24 | endif | 22 | endif |
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile index 3b037b6e0298..afa1e9e4e512 100644 --- a/drivers/gpu/host1x/Makefile +++ b/drivers/gpu/host1x/Makefile | |||
@@ -1,6 +1,5 @@ | |||
1 | ccflags-y = -Idrivers/gpu/host1x | ||
2 | |||
3 | host1x-y = \ | 1 | host1x-y = \ |
2 | bus.o \ | ||
4 | syncpt.o \ | 3 | syncpt.o \ |
5 | dev.o \ | 4 | dev.o \ |
6 | intr.o \ | 5 | intr.o \ |
@@ -8,13 +7,7 @@ host1x-y = \ | |||
8 | channel.o \ | 7 | channel.o \ |
9 | job.o \ | 8 | job.o \ |
10 | debug.o \ | 9 | debug.o \ |
11 | hw/host1x01.o | 10 | hw/host1x01.o \ |
12 | 11 | hw/host1x02.o | |
13 | ccflags-y += -Iinclude/drm | ||
14 | ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG | ||
15 | 12 | ||
16 | host1x-$(CONFIG_DRM_TEGRA) += drm/drm.o drm/fb.o drm/dc.o | ||
17 | host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o | ||
18 | host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o | ||
19 | host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o | ||
20 | obj-$(CONFIG_TEGRA_HOST1X) += host1x.o | 13 | obj-$(CONFIG_TEGRA_HOST1X) += host1x.o |
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c new file mode 100644 index 000000000000..509383f8be03 --- /dev/null +++ b/drivers/gpu/host1x/bus.c | |||
@@ -0,0 +1,550 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Avionic Design GmbH | ||
3 | * Copyright (C) 2012-2013, NVIDIA Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <linux/host1x.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include "dev.h" | ||
23 | |||
24 | static DEFINE_MUTEX(clients_lock); | ||
25 | static LIST_HEAD(clients); | ||
26 | |||
27 | static DEFINE_MUTEX(drivers_lock); | ||
28 | static LIST_HEAD(drivers); | ||
29 | |||
30 | static DEFINE_MUTEX(devices_lock); | ||
31 | static LIST_HEAD(devices); | ||
32 | |||
33 | struct host1x_subdev { | ||
34 | struct host1x_client *client; | ||
35 | struct device_node *np; | ||
36 | struct list_head list; | ||
37 | }; | ||
38 | |||
39 | /** | ||
40 | * host1x_subdev_add() - add a new subdevice with an associated device node | ||
41 | */ | ||
42 | static int host1x_subdev_add(struct host1x_device *device, | ||
43 | struct device_node *np) | ||
44 | { | ||
45 | struct host1x_subdev *subdev; | ||
46 | |||
47 | subdev = kzalloc(sizeof(*subdev), GFP_KERNEL); | ||
48 | if (!subdev) | ||
49 | return -ENOMEM; | ||
50 | |||
51 | INIT_LIST_HEAD(&subdev->list); | ||
52 | subdev->np = of_node_get(np); | ||
53 | |||
54 | mutex_lock(&device->subdevs_lock); | ||
55 | list_add_tail(&subdev->list, &device->subdevs); | ||
56 | mutex_unlock(&device->subdevs_lock); | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * host1x_subdev_del() - remove subdevice | ||
63 | */ | ||
64 | static void host1x_subdev_del(struct host1x_subdev *subdev) | ||
65 | { | ||
66 | list_del(&subdev->list); | ||
67 | of_node_put(subdev->np); | ||
68 | kfree(subdev); | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * host1x_device_parse_dt() - scan device tree and add matching subdevices | ||
73 | */ | ||
74 | static int host1x_device_parse_dt(struct host1x_device *device) | ||
75 | { | ||
76 | struct device_node *np; | ||
77 | int err; | ||
78 | |||
79 | for_each_child_of_node(device->dev.parent->of_node, np) { | ||
80 | if (of_match_node(device->driver->subdevs, np) && | ||
81 | of_device_is_available(np)) { | ||
82 | err = host1x_subdev_add(device, np); | ||
83 | if (err < 0) | ||
84 | return err; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static void host1x_subdev_register(struct host1x_device *device, | ||
92 | struct host1x_subdev *subdev, | ||
93 | struct host1x_client *client) | ||
94 | { | ||
95 | int err; | ||
96 | |||
97 | /* | ||
98 | * Move the subdevice to the list of active (registered) subdevices | ||
99 | * and associate it with a client. At the same time, associate the | ||
100 | * client with its parent device. | ||
101 | */ | ||
102 | mutex_lock(&device->subdevs_lock); | ||
103 | mutex_lock(&device->clients_lock); | ||
104 | list_move_tail(&client->list, &device->clients); | ||
105 | list_move_tail(&subdev->list, &device->active); | ||
106 | client->parent = &device->dev; | ||
107 | subdev->client = client; | ||
108 | mutex_unlock(&device->clients_lock); | ||
109 | mutex_unlock(&device->subdevs_lock); | ||
110 | |||
111 | /* | ||
112 | * When all subdevices have been registered, the composite device is | ||
113 | * ready to be probed. | ||
114 | */ | ||
115 | if (list_empty(&device->subdevs)) { | ||
116 | err = device->driver->probe(device); | ||
117 | if (err < 0) | ||
118 | dev_err(&device->dev, "probe failed: %d\n", err); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | static void __host1x_subdev_unregister(struct host1x_device *device, | ||
123 | struct host1x_subdev *subdev) | ||
124 | { | ||
125 | struct host1x_client *client = subdev->client; | ||
126 | int err; | ||
127 | |||
128 | /* | ||
129 | * If all subdevices have been activated, we're about to remove the | ||
130 | * first active subdevice, so unload the driver first. | ||
131 | */ | ||
132 | if (list_empty(&device->subdevs)) { | ||
133 | err = device->driver->remove(device); | ||
134 | if (err < 0) | ||
135 | dev_err(&device->dev, "remove failed: %d\n", err); | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Move the subdevice back to the list of idle subdevices and remove | ||
140 | * it from list of clients. | ||
141 | */ | ||
142 | mutex_lock(&device->clients_lock); | ||
143 | subdev->client = NULL; | ||
144 | client->parent = NULL; | ||
145 | list_move_tail(&subdev->list, &device->subdevs); | ||
146 | /* | ||
147 | * XXX: Perhaps don't do this here, but rather explicitly remove it | ||
148 | * when the device is about to be deleted. | ||
149 | * | ||
150 | * This is somewhat complicated by the fact that this function is | ||
151 | * used to remove the subdevice when a client is unregistered but | ||
152 | * also when the composite device is about to be removed. | ||
153 | */ | ||
154 | list_del_init(&client->list); | ||
155 | mutex_unlock(&device->clients_lock); | ||
156 | } | ||
157 | |||
158 | static void host1x_subdev_unregister(struct host1x_device *device, | ||
159 | struct host1x_subdev *subdev) | ||
160 | { | ||
161 | mutex_lock(&device->subdevs_lock); | ||
162 | __host1x_subdev_unregister(device, subdev); | ||
163 | mutex_unlock(&device->subdevs_lock); | ||
164 | } | ||
165 | |||
166 | int host1x_device_init(struct host1x_device *device) | ||
167 | { | ||
168 | struct host1x_client *client; | ||
169 | int err; | ||
170 | |||
171 | mutex_lock(&device->clients_lock); | ||
172 | |||
173 | list_for_each_entry(client, &device->clients, list) { | ||
174 | if (client->ops && client->ops->init) { | ||
175 | err = client->ops->init(client); | ||
176 | if (err < 0) { | ||
177 | dev_err(&device->dev, | ||
178 | "failed to initialize %s: %d\n", | ||
179 | dev_name(client->dev), err); | ||
180 | mutex_unlock(&device->clients_lock); | ||
181 | return err; | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | |||
186 | mutex_unlock(&device->clients_lock); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | int host1x_device_exit(struct host1x_device *device) | ||
192 | { | ||
193 | struct host1x_client *client; | ||
194 | int err; | ||
195 | |||
196 | mutex_lock(&device->clients_lock); | ||
197 | |||
198 | list_for_each_entry_reverse(client, &device->clients, list) { | ||
199 | if (client->ops && client->ops->exit) { | ||
200 | err = client->ops->exit(client); | ||
201 | if (err < 0) { | ||
202 | dev_err(&device->dev, | ||
203 | "failed to cleanup %s: %d\n", | ||
204 | dev_name(client->dev), err); | ||
205 | mutex_unlock(&device->clients_lock); | ||
206 | return err; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | mutex_unlock(&device->clients_lock); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int host1x_register_client(struct host1x *host1x, | ||
217 | struct host1x_client *client) | ||
218 | { | ||
219 | struct host1x_device *device; | ||
220 | struct host1x_subdev *subdev; | ||
221 | |||
222 | mutex_lock(&host1x->devices_lock); | ||
223 | |||
224 | list_for_each_entry(device, &host1x->devices, list) { | ||
225 | list_for_each_entry(subdev, &device->subdevs, list) { | ||
226 | if (subdev->np == client->dev->of_node) { | ||
227 | host1x_subdev_register(device, subdev, client); | ||
228 | mutex_unlock(&host1x->devices_lock); | ||
229 | return 0; | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | |||
234 | mutex_unlock(&host1x->devices_lock); | ||
235 | return -ENODEV; | ||
236 | } | ||
237 | |||
238 | static int host1x_unregister_client(struct host1x *host1x, | ||
239 | struct host1x_client *client) | ||
240 | { | ||
241 | struct host1x_device *device, *dt; | ||
242 | struct host1x_subdev *subdev; | ||
243 | |||
244 | mutex_lock(&host1x->devices_lock); | ||
245 | |||
246 | list_for_each_entry_safe(device, dt, &host1x->devices, list) { | ||
247 | list_for_each_entry(subdev, &device->active, list) { | ||
248 | if (subdev->client == client) { | ||
249 | host1x_subdev_unregister(device, subdev); | ||
250 | mutex_unlock(&host1x->devices_lock); | ||
251 | return 0; | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | |||
256 | mutex_unlock(&host1x->devices_lock); | ||
257 | return -ENODEV; | ||
258 | } | ||
259 | |||
260 | struct bus_type host1x_bus_type = { | ||
261 | .name = "host1x", | ||
262 | }; | ||
263 | |||
264 | int host1x_bus_init(void) | ||
265 | { | ||
266 | return bus_register(&host1x_bus_type); | ||
267 | } | ||
268 | |||
269 | void host1x_bus_exit(void) | ||
270 | { | ||
271 | bus_unregister(&host1x_bus_type); | ||
272 | } | ||
273 | |||
274 | static void host1x_device_release(struct device *dev) | ||
275 | { | ||
276 | struct host1x_device *device = to_host1x_device(dev); | ||
277 | |||
278 | kfree(device); | ||
279 | } | ||
280 | |||
281 | static int host1x_device_add(struct host1x *host1x, | ||
282 | struct host1x_driver *driver) | ||
283 | { | ||
284 | struct host1x_client *client, *tmp; | ||
285 | struct host1x_subdev *subdev; | ||
286 | struct host1x_device *device; | ||
287 | int err; | ||
288 | |||
289 | device = kzalloc(sizeof(*device), GFP_KERNEL); | ||
290 | if (!device) | ||
291 | return -ENOMEM; | ||
292 | |||
293 | mutex_init(&device->subdevs_lock); | ||
294 | INIT_LIST_HEAD(&device->subdevs); | ||
295 | INIT_LIST_HEAD(&device->active); | ||
296 | mutex_init(&device->clients_lock); | ||
297 | INIT_LIST_HEAD(&device->clients); | ||
298 | INIT_LIST_HEAD(&device->list); | ||
299 | device->driver = driver; | ||
300 | |||
301 | device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask; | ||
302 | device->dev.dma_mask = &device->dev.coherent_dma_mask; | ||
303 | device->dev.release = host1x_device_release; | ||
304 | dev_set_name(&device->dev, driver->name); | ||
305 | device->dev.bus = &host1x_bus_type; | ||
306 | device->dev.parent = host1x->dev; | ||
307 | |||
308 | err = device_register(&device->dev); | ||
309 | if (err < 0) | ||
310 | return err; | ||
311 | |||
312 | err = host1x_device_parse_dt(device); | ||
313 | if (err < 0) { | ||
314 | device_unregister(&device->dev); | ||
315 | return err; | ||
316 | } | ||
317 | |||
318 | mutex_lock(&host1x->devices_lock); | ||
319 | list_add_tail(&device->list, &host1x->devices); | ||
320 | mutex_unlock(&host1x->devices_lock); | ||
321 | |||
322 | mutex_lock(&clients_lock); | ||
323 | |||
324 | list_for_each_entry_safe(client, tmp, &clients, list) { | ||
325 | list_for_each_entry(subdev, &device->subdevs, list) { | ||
326 | if (subdev->np == client->dev->of_node) { | ||
327 | host1x_subdev_register(device, subdev, client); | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | mutex_unlock(&clients_lock); | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * Removes a device by first unregistering any subdevices and then removing | ||
340 | * itself from the list of devices. | ||
341 | * | ||
342 | * This function must be called with the host1x->devices_lock held. | ||
343 | */ | ||
344 | static void host1x_device_del(struct host1x *host1x, | ||
345 | struct host1x_device *device) | ||
346 | { | ||
347 | struct host1x_subdev *subdev, *sd; | ||
348 | struct host1x_client *client, *cl; | ||
349 | |||
350 | mutex_lock(&device->subdevs_lock); | ||
351 | |||
352 | /* unregister subdevices */ | ||
353 | list_for_each_entry_safe(subdev, sd, &device->active, list) { | ||
354 | /* | ||
355 | * host1x_subdev_unregister() will remove the client from | ||
356 | * any lists, so we'll need to manually add it back to the | ||
357 | * list of idle clients. | ||
358 | * | ||
359 | * XXX: Alternatively, perhaps don't remove the client from | ||
360 | * any lists in host1x_subdev_unregister() and instead do | ||
361 | * that explicitly from host1x_unregister_client()? | ||
362 | */ | ||
363 | client = subdev->client; | ||
364 | |||
365 | __host1x_subdev_unregister(device, subdev); | ||
366 | |||
367 | /* add the client to the list of idle clients */ | ||
368 | mutex_lock(&clients_lock); | ||
369 | list_add_tail(&client->list, &clients); | ||
370 | mutex_unlock(&clients_lock); | ||
371 | } | ||
372 | |||
373 | /* remove subdevices */ | ||
374 | list_for_each_entry_safe(subdev, sd, &device->subdevs, list) | ||
375 | host1x_subdev_del(subdev); | ||
376 | |||
377 | mutex_unlock(&device->subdevs_lock); | ||
378 | |||
379 | /* move clients to idle list */ | ||
380 | mutex_lock(&clients_lock); | ||
381 | mutex_lock(&device->clients_lock); | ||
382 | |||
383 | list_for_each_entry_safe(client, cl, &device->clients, list) | ||
384 | list_move_tail(&client->list, &clients); | ||
385 | |||
386 | mutex_unlock(&device->clients_lock); | ||
387 | mutex_unlock(&clients_lock); | ||
388 | |||
389 | /* finally remove the device */ | ||
390 | list_del_init(&device->list); | ||
391 | device_unregister(&device->dev); | ||
392 | } | ||
393 | |||
394 | static void host1x_attach_driver(struct host1x *host1x, | ||
395 | struct host1x_driver *driver) | ||
396 | { | ||
397 | struct host1x_device *device; | ||
398 | int err; | ||
399 | |||
400 | mutex_lock(&host1x->devices_lock); | ||
401 | |||
402 | list_for_each_entry(device, &host1x->devices, list) { | ||
403 | if (device->driver == driver) { | ||
404 | mutex_unlock(&host1x->devices_lock); | ||
405 | return; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | mutex_unlock(&host1x->devices_lock); | ||
410 | |||
411 | err = host1x_device_add(host1x, driver); | ||
412 | if (err < 0) | ||
413 | dev_err(host1x->dev, "failed to allocate device: %d\n", err); | ||
414 | } | ||
415 | |||
416 | static void host1x_detach_driver(struct host1x *host1x, | ||
417 | struct host1x_driver *driver) | ||
418 | { | ||
419 | struct host1x_device *device, *tmp; | ||
420 | |||
421 | mutex_lock(&host1x->devices_lock); | ||
422 | |||
423 | list_for_each_entry_safe(device, tmp, &host1x->devices, list) | ||
424 | if (device->driver == driver) | ||
425 | host1x_device_del(host1x, device); | ||
426 | |||
427 | mutex_unlock(&host1x->devices_lock); | ||
428 | } | ||
429 | |||
430 | int host1x_register(struct host1x *host1x) | ||
431 | { | ||
432 | struct host1x_driver *driver; | ||
433 | |||
434 | mutex_lock(&devices_lock); | ||
435 | list_add_tail(&host1x->list, &devices); | ||
436 | mutex_unlock(&devices_lock); | ||
437 | |||
438 | mutex_lock(&drivers_lock); | ||
439 | |||
440 | list_for_each_entry(driver, &drivers, list) | ||
441 | host1x_attach_driver(host1x, driver); | ||
442 | |||
443 | mutex_unlock(&drivers_lock); | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | int host1x_unregister(struct host1x *host1x) | ||
449 | { | ||
450 | struct host1x_driver *driver; | ||
451 | |||
452 | mutex_lock(&drivers_lock); | ||
453 | |||
454 | list_for_each_entry(driver, &drivers, list) | ||
455 | host1x_detach_driver(host1x, driver); | ||
456 | |||
457 | mutex_unlock(&drivers_lock); | ||
458 | |||
459 | mutex_lock(&devices_lock); | ||
460 | list_del_init(&host1x->list); | ||
461 | mutex_unlock(&devices_lock); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | int host1x_driver_register(struct host1x_driver *driver) | ||
467 | { | ||
468 | struct host1x *host1x; | ||
469 | |||
470 | INIT_LIST_HEAD(&driver->list); | ||
471 | |||
472 | mutex_lock(&drivers_lock); | ||
473 | list_add_tail(&driver->list, &drivers); | ||
474 | mutex_unlock(&drivers_lock); | ||
475 | |||
476 | mutex_lock(&devices_lock); | ||
477 | |||
478 | list_for_each_entry(host1x, &devices, list) | ||
479 | host1x_attach_driver(host1x, driver); | ||
480 | |||
481 | mutex_unlock(&devices_lock); | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | EXPORT_SYMBOL(host1x_driver_register); | ||
486 | |||
487 | void host1x_driver_unregister(struct host1x_driver *driver) | ||
488 | { | ||
489 | mutex_lock(&drivers_lock); | ||
490 | list_del_init(&driver->list); | ||
491 | mutex_unlock(&drivers_lock); | ||
492 | } | ||
493 | EXPORT_SYMBOL(host1x_driver_unregister); | ||
494 | |||
495 | int host1x_client_register(struct host1x_client *client) | ||
496 | { | ||
497 | struct host1x *host1x; | ||
498 | int err; | ||
499 | |||
500 | mutex_lock(&devices_lock); | ||
501 | |||
502 | list_for_each_entry(host1x, &devices, list) { | ||
503 | err = host1x_register_client(host1x, client); | ||
504 | if (!err) { | ||
505 | mutex_unlock(&devices_lock); | ||
506 | return 0; | ||
507 | } | ||
508 | } | ||
509 | |||
510 | mutex_unlock(&devices_lock); | ||
511 | |||
512 | mutex_lock(&clients_lock); | ||
513 | list_add_tail(&client->list, &clients); | ||
514 | mutex_unlock(&clients_lock); | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | EXPORT_SYMBOL(host1x_client_register); | ||
519 | |||
520 | int host1x_client_unregister(struct host1x_client *client) | ||
521 | { | ||
522 | struct host1x_client *c; | ||
523 | struct host1x *host1x; | ||
524 | int err; | ||
525 | |||
526 | mutex_lock(&devices_lock); | ||
527 | |||
528 | list_for_each_entry(host1x, &devices, list) { | ||
529 | err = host1x_unregister_client(host1x, client); | ||
530 | if (!err) { | ||
531 | mutex_unlock(&devices_lock); | ||
532 | return 0; | ||
533 | } | ||
534 | } | ||
535 | |||
536 | mutex_unlock(&devices_lock); | ||
537 | mutex_lock(&clients_lock); | ||
538 | |||
539 | list_for_each_entry(c, &clients, list) { | ||
540 | if (c == client) { | ||
541 | list_del_init(&c->list); | ||
542 | break; | ||
543 | } | ||
544 | } | ||
545 | |||
546 | mutex_unlock(&clients_lock); | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | EXPORT_SYMBOL(host1x_client_unregister); | ||
diff --git a/drivers/gpu/host1x/host1x_client.h b/drivers/gpu/host1x/bus.h index 9b85f10f4a44..4099e99212c8 100644 --- a/drivers/gpu/host1x/host1x_client.h +++ b/drivers/gpu/host1x/bus.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2013, NVIDIA Corporation. | 2 | * Copyright (C) 2012 Avionic Design GmbH |
3 | * Copyright (C) 2012-2013, NVIDIA Corporation | ||
3 | * | 4 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms and conditions of the GNU General Public License, | 6 | * under the terms and conditions of the GNU General Public License, |
@@ -14,22 +15,15 @@ | |||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | */ | 16 | */ |
16 | 17 | ||
17 | #ifndef HOST1X_CLIENT_H | 18 | #ifndef HOST1X_BUS_H |
18 | #define HOST1X_CLIENT_H | 19 | #define HOST1X_BUS_H |
19 | 20 | ||
20 | struct device; | 21 | struct host1x; |
21 | struct platform_device; | ||
22 | 22 | ||
23 | #ifdef CONFIG_DRM_TEGRA | 23 | int host1x_bus_init(void); |
24 | int host1x_drm_alloc(struct platform_device *pdev); | 24 | void host1x_bus_exit(void); |
25 | #else | ||
26 | static inline int host1x_drm_alloc(struct platform_device *pdev) | ||
27 | { | ||
28 | return 0; | ||
29 | } | ||
30 | #endif | ||
31 | 25 | ||
32 | void host1x_set_drm_data(struct device *dev, void *data); | 26 | int host1x_register(struct host1x *host1x); |
33 | void *host1x_get_drm_data(struct device *dev); | 27 | int host1x_unregister(struct host1x *host1x); |
34 | 28 | ||
35 | #endif | 29 | #endif |
diff --git a/drivers/gpu/host1x/cdma.c b/drivers/gpu/host1x/cdma.c index de72172d3b5f..3995255b16c7 100644 --- a/drivers/gpu/host1x/cdma.c +++ b/drivers/gpu/host1x/cdma.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <asm/cacheflush.h> | 20 | #include <asm/cacheflush.h> |
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <linux/dma-mapping.h> | 22 | #include <linux/dma-mapping.h> |
23 | #include <linux/host1x.h> | ||
23 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
24 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
25 | #include <linux/kfifo.h> | 26 | #include <linux/kfifo.h> |
@@ -30,7 +31,6 @@ | |||
30 | #include "channel.h" | 31 | #include "channel.h" |
31 | #include "dev.h" | 32 | #include "dev.h" |
32 | #include "debug.h" | 33 | #include "debug.h" |
33 | #include "host1x_bo.h" | ||
34 | #include "job.h" | 34 | #include "job.h" |
35 | 35 | ||
36 | /* | 36 | /* |
diff --git a/drivers/gpu/host1x/channel.h b/drivers/gpu/host1x/channel.h index 48723b8eea42..df767cf90d51 100644 --- a/drivers/gpu/host1x/channel.h +++ b/drivers/gpu/host1x/channel.h | |||
@@ -40,12 +40,6 @@ struct host1x_channel { | |||
40 | /* channel list operations */ | 40 | /* channel list operations */ |
41 | int host1x_channel_list_init(struct host1x *host); | 41 | int host1x_channel_list_init(struct host1x *host); |
42 | 42 | ||
43 | struct host1x_channel *host1x_channel_request(struct device *dev); | ||
44 | void host1x_channel_free(struct host1x_channel *channel); | ||
45 | struct host1x_channel *host1x_channel_get(struct host1x_channel *channel); | ||
46 | void host1x_channel_put(struct host1x_channel *channel); | ||
47 | int host1x_job_submit(struct host1x_job *job); | ||
48 | |||
49 | #define host1x_for_each_channel(host, channel) \ | 43 | #define host1x_for_each_channel(host, channel) \ |
50 | list_for_each_entry(channel, &host->chlist.list, list) | 44 | list_for_each_entry(channel, &host->chlist.list, list) |
51 | 45 | ||
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 471630299878..80da003d63de 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c | |||
@@ -27,24 +27,13 @@ | |||
27 | #define CREATE_TRACE_POINTS | 27 | #define CREATE_TRACE_POINTS |
28 | #include <trace/events/host1x.h> | 28 | #include <trace/events/host1x.h> |
29 | 29 | ||
30 | #include "bus.h" | ||
30 | #include "dev.h" | 31 | #include "dev.h" |
31 | #include "intr.h" | 32 | #include "intr.h" |
32 | #include "channel.h" | 33 | #include "channel.h" |
33 | #include "debug.h" | 34 | #include "debug.h" |
34 | #include "hw/host1x01.h" | 35 | #include "hw/host1x01.h" |
35 | #include "host1x_client.h" | 36 | #include "hw/host1x02.h" |
36 | |||
37 | void host1x_set_drm_data(struct device *dev, void *data) | ||
38 | { | ||
39 | struct host1x *host1x = dev_get_drvdata(dev); | ||
40 | host1x->drm_data = data; | ||
41 | } | ||
42 | |||
43 | void *host1x_get_drm_data(struct device *dev) | ||
44 | { | ||
45 | struct host1x *host1x = dev_get_drvdata(dev); | ||
46 | return host1x ? host1x->drm_data : NULL; | ||
47 | } | ||
48 | 37 | ||
49 | void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) | 38 | void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) |
50 | { | 39 | { |
@@ -79,7 +68,17 @@ static const struct host1x_info host1x01_info = { | |||
79 | .sync_offset = 0x3000, | 68 | .sync_offset = 0x3000, |
80 | }; | 69 | }; |
81 | 70 | ||
71 | static const struct host1x_info host1x02_info = { | ||
72 | .nb_channels = 9, | ||
73 | .nb_pts = 32, | ||
74 | .nb_mlocks = 16, | ||
75 | .nb_bases = 12, | ||
76 | .init = host1x02_init, | ||
77 | .sync_offset = 0x3000, | ||
78 | }; | ||
79 | |||
82 | static struct of_device_id host1x_of_match[] = { | 80 | static struct of_device_id host1x_of_match[] = { |
81 | { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, }, | ||
83 | { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, }, | 82 | { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, }, |
84 | { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, }, | 83 | { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, }, |
85 | { }, | 84 | { }, |
@@ -114,6 +113,9 @@ static int host1x_probe(struct platform_device *pdev) | |||
114 | if (!host) | 113 | if (!host) |
115 | return -ENOMEM; | 114 | return -ENOMEM; |
116 | 115 | ||
116 | mutex_init(&host->devices_lock); | ||
117 | INIT_LIST_HEAD(&host->devices); | ||
118 | INIT_LIST_HEAD(&host->list); | ||
117 | host->dev = &pdev->dev; | 119 | host->dev = &pdev->dev; |
118 | host->info = id->data; | 120 | host->info = id->data; |
119 | 121 | ||
@@ -152,7 +154,7 @@ static int host1x_probe(struct platform_device *pdev) | |||
152 | err = host1x_syncpt_init(host); | 154 | err = host1x_syncpt_init(host); |
153 | if (err) { | 155 | if (err) { |
154 | dev_err(&pdev->dev, "failed to initialize syncpts\n"); | 156 | dev_err(&pdev->dev, "failed to initialize syncpts\n"); |
155 | return err; | 157 | goto fail_unprepare_disable; |
156 | } | 158 | } |
157 | 159 | ||
158 | err = host1x_intr_init(host, syncpt_irq); | 160 | err = host1x_intr_init(host, syncpt_irq); |
@@ -163,19 +165,26 @@ static int host1x_probe(struct platform_device *pdev) | |||
163 | 165 | ||
164 | host1x_debug_init(host); | 166 | host1x_debug_init(host); |
165 | 167 | ||
166 | host1x_drm_alloc(pdev); | 168 | err = host1x_register(host); |
169 | if (err < 0) | ||
170 | goto fail_deinit_intr; | ||
167 | 171 | ||
168 | return 0; | 172 | return 0; |
169 | 173 | ||
174 | fail_deinit_intr: | ||
175 | host1x_intr_deinit(host); | ||
170 | fail_deinit_syncpt: | 176 | fail_deinit_syncpt: |
171 | host1x_syncpt_deinit(host); | 177 | host1x_syncpt_deinit(host); |
178 | fail_unprepare_disable: | ||
179 | clk_disable_unprepare(host->clk); | ||
172 | return err; | 180 | return err; |
173 | } | 181 | } |
174 | 182 | ||
175 | static int __exit host1x_remove(struct platform_device *pdev) | 183 | static int host1x_remove(struct platform_device *pdev) |
176 | { | 184 | { |
177 | struct host1x *host = platform_get_drvdata(pdev); | 185 | struct host1x *host = platform_get_drvdata(pdev); |
178 | 186 | ||
187 | host1x_unregister(host); | ||
179 | host1x_intr_deinit(host); | 188 | host1x_intr_deinit(host); |
180 | host1x_syncpt_deinit(host); | 189 | host1x_syncpt_deinit(host); |
181 | clk_disable_unprepare(host->clk); | 190 | clk_disable_unprepare(host->clk); |
@@ -184,59 +193,36 @@ static int __exit host1x_remove(struct platform_device *pdev) | |||
184 | } | 193 | } |
185 | 194 | ||
186 | static struct platform_driver tegra_host1x_driver = { | 195 | static struct platform_driver tegra_host1x_driver = { |
187 | .probe = host1x_probe, | ||
188 | .remove = __exit_p(host1x_remove), | ||
189 | .driver = { | 196 | .driver = { |
190 | .owner = THIS_MODULE, | ||
191 | .name = "tegra-host1x", | 197 | .name = "tegra-host1x", |
192 | .of_match_table = host1x_of_match, | 198 | .of_match_table = host1x_of_match, |
193 | }, | 199 | }, |
200 | .probe = host1x_probe, | ||
201 | .remove = host1x_remove, | ||
194 | }; | 202 | }; |
195 | 203 | ||
196 | static int __init tegra_host1x_init(void) | 204 | static int __init tegra_host1x_init(void) |
197 | { | 205 | { |
198 | int err; | 206 | int err; |
199 | 207 | ||
200 | err = platform_driver_register(&tegra_host1x_driver); | 208 | err = host1x_bus_init(); |
201 | if (err < 0) | 209 | if (err < 0) |
202 | return err; | 210 | return err; |
203 | 211 | ||
204 | #ifdef CONFIG_DRM_TEGRA | 212 | err = platform_driver_register(&tegra_host1x_driver); |
205 | err = platform_driver_register(&tegra_dc_driver); | 213 | if (err < 0) { |
206 | if (err < 0) | 214 | host1x_bus_exit(); |
207 | goto unregister_host1x; | 215 | return err; |
208 | 216 | } | |
209 | err = platform_driver_register(&tegra_hdmi_driver); | ||
210 | if (err < 0) | ||
211 | goto unregister_dc; | ||
212 | |||
213 | err = platform_driver_register(&tegra_gr2d_driver); | ||
214 | if (err < 0) | ||
215 | goto unregister_hdmi; | ||
216 | #endif | ||
217 | 217 | ||
218 | return 0; | 218 | return 0; |
219 | |||
220 | #ifdef CONFIG_DRM_TEGRA | ||
221 | unregister_hdmi: | ||
222 | platform_driver_unregister(&tegra_hdmi_driver); | ||
223 | unregister_dc: | ||
224 | platform_driver_unregister(&tegra_dc_driver); | ||
225 | unregister_host1x: | ||
226 | platform_driver_unregister(&tegra_host1x_driver); | ||
227 | return err; | ||
228 | #endif | ||
229 | } | 219 | } |
230 | module_init(tegra_host1x_init); | 220 | module_init(tegra_host1x_init); |
231 | 221 | ||
232 | static void __exit tegra_host1x_exit(void) | 222 | static void __exit tegra_host1x_exit(void) |
233 | { | 223 | { |
234 | #ifdef CONFIG_DRM_TEGRA | ||
235 | platform_driver_unregister(&tegra_gr2d_driver); | ||
236 | platform_driver_unregister(&tegra_hdmi_driver); | ||
237 | platform_driver_unregister(&tegra_dc_driver); | ||
238 | #endif | ||
239 | platform_driver_unregister(&tegra_host1x_driver); | 224 | platform_driver_unregister(&tegra_host1x_driver); |
225 | host1x_bus_exit(); | ||
240 | } | 226 | } |
241 | module_exit(tegra_host1x_exit); | 227 | module_exit(tegra_host1x_exit); |
242 | 228 | ||
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index bed90a8131be..a61a976e7a42 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "job.h" | 27 | #include "job.h" |
28 | 28 | ||
29 | struct host1x_syncpt; | 29 | struct host1x_syncpt; |
30 | struct host1x_syncpt_base; | ||
30 | struct host1x_channel; | 31 | struct host1x_channel; |
31 | struct host1x_cdma; | 32 | struct host1x_cdma; |
32 | struct host1x_job; | 33 | struct host1x_job; |
@@ -102,6 +103,7 @@ struct host1x { | |||
102 | 103 | ||
103 | void __iomem *regs; | 104 | void __iomem *regs; |
104 | struct host1x_syncpt *syncpt; | 105 | struct host1x_syncpt *syncpt; |
106 | struct host1x_syncpt_base *bases; | ||
105 | struct device *dev; | 107 | struct device *dev; |
106 | struct clk *clk; | 108 | struct clk *clk; |
107 | 109 | ||
@@ -125,7 +127,10 @@ struct host1x { | |||
125 | 127 | ||
126 | struct dentry *debugfs; | 128 | struct dentry *debugfs; |
127 | 129 | ||
128 | void *drm_data; | 130 | struct mutex devices_lock; |
131 | struct list_head devices; | ||
132 | |||
133 | struct list_head list; | ||
129 | }; | 134 | }; |
130 | 135 | ||
131 | void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); | 136 | void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); |
@@ -301,8 +306,4 @@ static inline void host1x_hw_show_mlocks(struct host1x *host, struct output *o) | |||
301 | host->debug_op->show_mlocks(host, o); | 306 | host->debug_op->show_mlocks(host, o); |
302 | } | 307 | } |
303 | 308 | ||
304 | extern struct platform_driver tegra_dc_driver; | ||
305 | extern struct platform_driver tegra_hdmi_driver; | ||
306 | extern struct platform_driver tegra_gr2d_driver; | ||
307 | |||
308 | #endif | 309 | #endif |
diff --git a/drivers/gpu/host1x/drm/Kconfig b/drivers/gpu/host1x/drm/Kconfig deleted file mode 100644 index 69853a4de40a..000000000000 --- a/drivers/gpu/host1x/drm/Kconfig +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | config DRM_TEGRA | ||
2 | bool "NVIDIA Tegra DRM" | ||
3 | depends on DRM | ||
4 | select DRM_KMS_HELPER | ||
5 | select FB_SYS_FILLRECT | ||
6 | select FB_SYS_COPYAREA | ||
7 | select FB_SYS_IMAGEBLIT | ||
8 | help | ||
9 | Choose this option if you have an NVIDIA Tegra SoC. | ||
10 | |||
11 | To compile this driver as a module, choose M here: the module | ||
12 | will be called tegra-drm. | ||
13 | |||
14 | if DRM_TEGRA | ||
15 | |||
16 | config DRM_TEGRA_STAGING | ||
17 | bool "Enable HOST1X interface" | ||
18 | depends on STAGING | ||
19 | help | ||
20 | Say yes if HOST1X should be available for userspace DRM users. | ||
21 | |||
22 | If unsure, choose N. | ||
23 | |||
24 | config DRM_TEGRA_DEBUG | ||
25 | bool "NVIDIA Tegra DRM debug support" | ||
26 | help | ||
27 | Say yes here to enable debugging support. | ||
28 | |||
29 | endif | ||
diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c deleted file mode 100644 index b1a05ad901c3..000000000000 --- a/drivers/gpu/host1x/drm/dc.c +++ /dev/null | |||
@@ -1,1200 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Avionic Design GmbH | ||
3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/debugfs.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/of.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/clk/tegra.h> | ||
16 | |||
17 | #include "host1x_client.h" | ||
18 | #include "dc.h" | ||
19 | #include "drm.h" | ||
20 | #include "gem.h" | ||
21 | |||
22 | struct tegra_plane { | ||
23 | struct drm_plane base; | ||
24 | unsigned int index; | ||
25 | }; | ||
26 | |||
27 | static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane) | ||
28 | { | ||
29 | return container_of(plane, struct tegra_plane, base); | ||
30 | } | ||
31 | |||
32 | static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | ||
33 | struct drm_framebuffer *fb, int crtc_x, | ||
34 | int crtc_y, unsigned int crtc_w, | ||
35 | unsigned int crtc_h, uint32_t src_x, | ||
36 | uint32_t src_y, uint32_t src_w, uint32_t src_h) | ||
37 | { | ||
38 | struct tegra_plane *p = to_tegra_plane(plane); | ||
39 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
40 | struct tegra_dc_window window; | ||
41 | unsigned int i; | ||
42 | |||
43 | memset(&window, 0, sizeof(window)); | ||
44 | window.src.x = src_x >> 16; | ||
45 | window.src.y = src_y >> 16; | ||
46 | window.src.w = src_w >> 16; | ||
47 | window.src.h = src_h >> 16; | ||
48 | window.dst.x = crtc_x; | ||
49 | window.dst.y = crtc_y; | ||
50 | window.dst.w = crtc_w; | ||
51 | window.dst.h = crtc_h; | ||
52 | window.format = tegra_dc_format(fb->pixel_format); | ||
53 | window.bits_per_pixel = fb->bits_per_pixel; | ||
54 | |||
55 | for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { | ||
56 | struct tegra_bo *bo = tegra_fb_get_plane(fb, i); | ||
57 | |||
58 | window.base[i] = bo->paddr + fb->offsets[i]; | ||
59 | |||
60 | /* | ||
61 | * Tegra doesn't support different strides for U and V planes | ||
62 | * so we display a warning if the user tries to display a | ||
63 | * framebuffer with such a configuration. | ||
64 | */ | ||
65 | if (i >= 2) { | ||
66 | if (fb->pitches[i] != window.stride[1]) | ||
67 | DRM_ERROR("unsupported UV-plane configuration\n"); | ||
68 | } else { | ||
69 | window.stride[i] = fb->pitches[i]; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | return tegra_dc_setup_window(dc, p->index, &window); | ||
74 | } | ||
75 | |||
76 | static int tegra_plane_disable(struct drm_plane *plane) | ||
77 | { | ||
78 | struct tegra_dc *dc = to_tegra_dc(plane->crtc); | ||
79 | struct tegra_plane *p = to_tegra_plane(plane); | ||
80 | unsigned long value; | ||
81 | |||
82 | if (!plane->crtc) | ||
83 | return 0; | ||
84 | |||
85 | value = WINDOW_A_SELECT << p->index; | ||
86 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
87 | |||
88 | value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); | ||
89 | value &= ~WIN_ENABLE; | ||
90 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
91 | |||
92 | tegra_dc_writel(dc, WIN_A_UPDATE << p->index, DC_CMD_STATE_CONTROL); | ||
93 | tegra_dc_writel(dc, WIN_A_ACT_REQ << p->index, DC_CMD_STATE_CONTROL); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static void tegra_plane_destroy(struct drm_plane *plane) | ||
99 | { | ||
100 | tegra_plane_disable(plane); | ||
101 | drm_plane_cleanup(plane); | ||
102 | } | ||
103 | |||
104 | static const struct drm_plane_funcs tegra_plane_funcs = { | ||
105 | .update_plane = tegra_plane_update, | ||
106 | .disable_plane = tegra_plane_disable, | ||
107 | .destroy = tegra_plane_destroy, | ||
108 | }; | ||
109 | |||
110 | static const uint32_t plane_formats[] = { | ||
111 | DRM_FORMAT_XBGR8888, | ||
112 | DRM_FORMAT_XRGB8888, | ||
113 | DRM_FORMAT_RGB565, | ||
114 | DRM_FORMAT_UYVY, | ||
115 | DRM_FORMAT_YUV420, | ||
116 | DRM_FORMAT_YUV422, | ||
117 | }; | ||
118 | |||
119 | static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) | ||
120 | { | ||
121 | unsigned int i; | ||
122 | int err = 0; | ||
123 | |||
124 | for (i = 0; i < 2; i++) { | ||
125 | struct tegra_plane *plane; | ||
126 | |||
127 | plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL); | ||
128 | if (!plane) | ||
129 | return -ENOMEM; | ||
130 | |||
131 | plane->index = 1 + i; | ||
132 | |||
133 | err = drm_plane_init(drm, &plane->base, 1 << dc->pipe, | ||
134 | &tegra_plane_funcs, plane_formats, | ||
135 | ARRAY_SIZE(plane_formats), false); | ||
136 | if (err < 0) | ||
137 | return err; | ||
138 | } | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, | ||
144 | struct drm_framebuffer *fb) | ||
145 | { | ||
146 | unsigned int format = tegra_dc_format(fb->pixel_format); | ||
147 | struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); | ||
148 | unsigned long value; | ||
149 | |||
150 | tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
151 | |||
152 | value = fb->offsets[0] + y * fb->pitches[0] + | ||
153 | x * fb->bits_per_pixel / 8; | ||
154 | |||
155 | tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR); | ||
156 | tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE); | ||
157 | tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH); | ||
158 | |||
159 | value = GENERAL_UPDATE | WIN_A_UPDATE; | ||
160 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
161 | |||
162 | value = GENERAL_ACT_REQ | WIN_A_ACT_REQ; | ||
163 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | void tegra_dc_enable_vblank(struct tegra_dc *dc) | ||
169 | { | ||
170 | unsigned long value, flags; | ||
171 | |||
172 | spin_lock_irqsave(&dc->lock, flags); | ||
173 | |||
174 | value = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
175 | value |= VBLANK_INT; | ||
176 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
177 | |||
178 | spin_unlock_irqrestore(&dc->lock, flags); | ||
179 | } | ||
180 | |||
181 | void tegra_dc_disable_vblank(struct tegra_dc *dc) | ||
182 | { | ||
183 | unsigned long value, flags; | ||
184 | |||
185 | spin_lock_irqsave(&dc->lock, flags); | ||
186 | |||
187 | value = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
188 | value &= ~VBLANK_INT; | ||
189 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
190 | |||
191 | spin_unlock_irqrestore(&dc->lock, flags); | ||
192 | } | ||
193 | |||
194 | static void tegra_dc_finish_page_flip(struct tegra_dc *dc) | ||
195 | { | ||
196 | struct drm_device *drm = dc->base.dev; | ||
197 | struct drm_crtc *crtc = &dc->base; | ||
198 | unsigned long flags, base; | ||
199 | struct tegra_bo *bo; | ||
200 | |||
201 | if (!dc->event) | ||
202 | return; | ||
203 | |||
204 | bo = tegra_fb_get_plane(crtc->fb, 0); | ||
205 | |||
206 | /* check if new start address has been latched */ | ||
207 | tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); | ||
208 | base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR); | ||
209 | tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); | ||
210 | |||
211 | if (base == bo->paddr + crtc->fb->offsets[0]) { | ||
212 | spin_lock_irqsave(&drm->event_lock, flags); | ||
213 | drm_send_vblank_event(drm, dc->pipe, dc->event); | ||
214 | drm_vblank_put(drm, dc->pipe); | ||
215 | dc->event = NULL; | ||
216 | spin_unlock_irqrestore(&drm->event_lock, flags); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) | ||
221 | { | ||
222 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
223 | struct drm_device *drm = crtc->dev; | ||
224 | unsigned long flags; | ||
225 | |||
226 | spin_lock_irqsave(&drm->event_lock, flags); | ||
227 | |||
228 | if (dc->event && dc->event->base.file_priv == file) { | ||
229 | dc->event->base.destroy(&dc->event->base); | ||
230 | drm_vblank_put(drm, dc->pipe); | ||
231 | dc->event = NULL; | ||
232 | } | ||
233 | |||
234 | spin_unlock_irqrestore(&drm->event_lock, flags); | ||
235 | } | ||
236 | |||
237 | static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | ||
238 | struct drm_pending_vblank_event *event, uint32_t page_flip_flags) | ||
239 | { | ||
240 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
241 | struct drm_device *drm = crtc->dev; | ||
242 | |||
243 | if (dc->event) | ||
244 | return -EBUSY; | ||
245 | |||
246 | if (event) { | ||
247 | event->pipe = dc->pipe; | ||
248 | dc->event = event; | ||
249 | drm_vblank_get(drm, dc->pipe); | ||
250 | } | ||
251 | |||
252 | tegra_dc_set_base(dc, 0, 0, fb); | ||
253 | crtc->fb = fb; | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static const struct drm_crtc_funcs tegra_crtc_funcs = { | ||
259 | .page_flip = tegra_dc_page_flip, | ||
260 | .set_config = drm_crtc_helper_set_config, | ||
261 | .destroy = drm_crtc_cleanup, | ||
262 | }; | ||
263 | |||
264 | static void tegra_crtc_disable(struct drm_crtc *crtc) | ||
265 | { | ||
266 | struct drm_device *drm = crtc->dev; | ||
267 | struct drm_plane *plane; | ||
268 | |||
269 | list_for_each_entry(plane, &drm->mode_config.plane_list, head) { | ||
270 | if (plane->crtc == crtc) { | ||
271 | tegra_plane_disable(plane); | ||
272 | plane->crtc = NULL; | ||
273 | |||
274 | if (plane->fb) { | ||
275 | drm_framebuffer_unreference(plane->fb); | ||
276 | plane->fb = NULL; | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, | ||
283 | const struct drm_display_mode *mode, | ||
284 | struct drm_display_mode *adjusted) | ||
285 | { | ||
286 | return true; | ||
287 | } | ||
288 | |||
289 | static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v, | ||
290 | unsigned int bpp) | ||
291 | { | ||
292 | fixed20_12 outf = dfixed_init(out); | ||
293 | fixed20_12 inf = dfixed_init(in); | ||
294 | u32 dda_inc; | ||
295 | int max; | ||
296 | |||
297 | if (v) | ||
298 | max = 15; | ||
299 | else { | ||
300 | switch (bpp) { | ||
301 | case 2: | ||
302 | max = 8; | ||
303 | break; | ||
304 | |||
305 | default: | ||
306 | WARN_ON_ONCE(1); | ||
307 | /* fallthrough */ | ||
308 | case 4: | ||
309 | max = 4; | ||
310 | break; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1)); | ||
315 | inf.full -= dfixed_const(1); | ||
316 | |||
317 | dda_inc = dfixed_div(inf, outf); | ||
318 | dda_inc = min_t(u32, dda_inc, dfixed_const(max)); | ||
319 | |||
320 | return dda_inc; | ||
321 | } | ||
322 | |||
323 | static inline u32 compute_initial_dda(unsigned int in) | ||
324 | { | ||
325 | fixed20_12 inf = dfixed_init(in); | ||
326 | return dfixed_frac(inf); | ||
327 | } | ||
328 | |||
329 | static int tegra_dc_set_timings(struct tegra_dc *dc, | ||
330 | struct drm_display_mode *mode) | ||
331 | { | ||
332 | /* TODO: For HDMI compliance, h & v ref_to_sync should be set to 1 */ | ||
333 | unsigned int h_ref_to_sync = 0; | ||
334 | unsigned int v_ref_to_sync = 0; | ||
335 | unsigned long value; | ||
336 | |||
337 | tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS); | ||
338 | |||
339 | value = (v_ref_to_sync << 16) | h_ref_to_sync; | ||
340 | tegra_dc_writel(dc, value, DC_DISP_REF_TO_SYNC); | ||
341 | |||
342 | value = ((mode->vsync_end - mode->vsync_start) << 16) | | ||
343 | ((mode->hsync_end - mode->hsync_start) << 0); | ||
344 | tegra_dc_writel(dc, value, DC_DISP_SYNC_WIDTH); | ||
345 | |||
346 | value = ((mode->vtotal - mode->vsync_end) << 16) | | ||
347 | ((mode->htotal - mode->hsync_end) << 0); | ||
348 | tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH); | ||
349 | |||
350 | value = ((mode->vsync_start - mode->vdisplay) << 16) | | ||
351 | ((mode->hsync_start - mode->hdisplay) << 0); | ||
352 | tegra_dc_writel(dc, value, DC_DISP_FRONT_PORCH); | ||
353 | |||
354 | value = (mode->vdisplay << 16) | mode->hdisplay; | ||
355 | tegra_dc_writel(dc, value, DC_DISP_ACTIVE); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int tegra_crtc_setup_clk(struct drm_crtc *crtc, | ||
361 | struct drm_display_mode *mode, | ||
362 | unsigned long *div) | ||
363 | { | ||
364 | unsigned long pclk = mode->clock * 1000, rate; | ||
365 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
366 | struct tegra_output *output = NULL; | ||
367 | struct drm_encoder *encoder; | ||
368 | long err; | ||
369 | |||
370 | list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, head) | ||
371 | if (encoder->crtc == crtc) { | ||
372 | output = encoder_to_output(encoder); | ||
373 | break; | ||
374 | } | ||
375 | |||
376 | if (!output) | ||
377 | return -ENODEV; | ||
378 | |||
379 | /* | ||
380 | * This assumes that the display controller will divide its parent | ||
381 | * clock by 2 to generate the pixel clock. | ||
382 | */ | ||
383 | err = tegra_output_setup_clock(output, dc->clk, pclk * 2); | ||
384 | if (err < 0) { | ||
385 | dev_err(dc->dev, "failed to setup clock: %ld\n", err); | ||
386 | return err; | ||
387 | } | ||
388 | |||
389 | rate = clk_get_rate(dc->clk); | ||
390 | *div = (rate * 2 / pclk) - 2; | ||
391 | |||
392 | DRM_DEBUG_KMS("rate: %lu, div: %lu\n", rate, *div); | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar) | ||
398 | { | ||
399 | switch (format) { | ||
400 | case WIN_COLOR_DEPTH_YCbCr422: | ||
401 | case WIN_COLOR_DEPTH_YUV422: | ||
402 | if (planar) | ||
403 | *planar = false; | ||
404 | |||
405 | return true; | ||
406 | |||
407 | case WIN_COLOR_DEPTH_YCbCr420P: | ||
408 | case WIN_COLOR_DEPTH_YUV420P: | ||
409 | case WIN_COLOR_DEPTH_YCbCr422P: | ||
410 | case WIN_COLOR_DEPTH_YUV422P: | ||
411 | case WIN_COLOR_DEPTH_YCbCr422R: | ||
412 | case WIN_COLOR_DEPTH_YUV422R: | ||
413 | case WIN_COLOR_DEPTH_YCbCr422RA: | ||
414 | case WIN_COLOR_DEPTH_YUV422RA: | ||
415 | if (planar) | ||
416 | *planar = true; | ||
417 | |||
418 | return true; | ||
419 | } | ||
420 | |||
421 | return false; | ||
422 | } | ||
423 | |||
424 | int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | ||
425 | const struct tegra_dc_window *window) | ||
426 | { | ||
427 | unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; | ||
428 | unsigned long value; | ||
429 | bool yuv, planar; | ||
430 | |||
431 | /* | ||
432 | * For YUV planar modes, the number of bytes per pixel takes into | ||
433 | * account only the luma component and therefore is 1. | ||
434 | */ | ||
435 | yuv = tegra_dc_format_is_yuv(window->format, &planar); | ||
436 | if (!yuv) | ||
437 | bpp = window->bits_per_pixel / 8; | ||
438 | else | ||
439 | bpp = planar ? 1 : 2; | ||
440 | |||
441 | value = WINDOW_A_SELECT << index; | ||
442 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
443 | |||
444 | tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH); | ||
445 | tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP); | ||
446 | |||
447 | value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x); | ||
448 | tegra_dc_writel(dc, value, DC_WIN_POSITION); | ||
449 | |||
450 | value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w); | ||
451 | tegra_dc_writel(dc, value, DC_WIN_SIZE); | ||
452 | |||
453 | h_offset = window->src.x * bpp; | ||
454 | v_offset = window->src.y; | ||
455 | h_size = window->src.w * bpp; | ||
456 | v_size = window->src.h; | ||
457 | |||
458 | value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size); | ||
459 | tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE); | ||
460 | |||
461 | /* | ||
462 | * For DDA computations the number of bytes per pixel for YUV planar | ||
463 | * modes needs to take into account all Y, U and V components. | ||
464 | */ | ||
465 | if (yuv && planar) | ||
466 | bpp = 2; | ||
467 | |||
468 | h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp); | ||
469 | v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp); | ||
470 | |||
471 | value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda); | ||
472 | tegra_dc_writel(dc, value, DC_WIN_DDA_INC); | ||
473 | |||
474 | h_dda = compute_initial_dda(window->src.x); | ||
475 | v_dda = compute_initial_dda(window->src.y); | ||
476 | |||
477 | tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA); | ||
478 | tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA); | ||
479 | |||
480 | tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE); | ||
481 | tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE); | ||
482 | |||
483 | tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR); | ||
484 | |||
485 | if (yuv && planar) { | ||
486 | tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U); | ||
487 | tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V); | ||
488 | value = window->stride[1] << 16 | window->stride[0]; | ||
489 | tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE); | ||
490 | } else { | ||
491 | tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE); | ||
492 | } | ||
493 | |||
494 | tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); | ||
495 | tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); | ||
496 | |||
497 | value = WIN_ENABLE; | ||
498 | |||
499 | if (yuv) { | ||
500 | /* setup default colorspace conversion coefficients */ | ||
501 | tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF); | ||
502 | tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB); | ||
503 | tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR); | ||
504 | tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR); | ||
505 | tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG); | ||
506 | tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG); | ||
507 | tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB); | ||
508 | tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB); | ||
509 | |||
510 | value |= CSC_ENABLE; | ||
511 | } else if (window->bits_per_pixel < 24) { | ||
512 | value |= COLOR_EXPAND; | ||
513 | } | ||
514 | |||
515 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
516 | |||
517 | /* | ||
518 | * Disable blending and assume Window A is the bottom-most window, | ||
519 | * Window C is the top-most window and Window B is in the middle. | ||
520 | */ | ||
521 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY); | ||
522 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN); | ||
523 | |||
524 | switch (index) { | ||
525 | case 0: | ||
526 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X); | ||
527 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); | ||
528 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); | ||
529 | break; | ||
530 | |||
531 | case 1: | ||
532 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); | ||
533 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); | ||
534 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); | ||
535 | break; | ||
536 | |||
537 | case 2: | ||
538 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); | ||
539 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y); | ||
540 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY); | ||
541 | break; | ||
542 | } | ||
543 | |||
544 | tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL); | ||
545 | tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL); | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | unsigned int tegra_dc_format(uint32_t format) | ||
551 | { | ||
552 | switch (format) { | ||
553 | case DRM_FORMAT_XBGR8888: | ||
554 | return WIN_COLOR_DEPTH_R8G8B8A8; | ||
555 | |||
556 | case DRM_FORMAT_XRGB8888: | ||
557 | return WIN_COLOR_DEPTH_B8G8R8A8; | ||
558 | |||
559 | case DRM_FORMAT_RGB565: | ||
560 | return WIN_COLOR_DEPTH_B5G6R5; | ||
561 | |||
562 | case DRM_FORMAT_UYVY: | ||
563 | return WIN_COLOR_DEPTH_YCbCr422; | ||
564 | |||
565 | case DRM_FORMAT_YUV420: | ||
566 | return WIN_COLOR_DEPTH_YCbCr420P; | ||
567 | |||
568 | case DRM_FORMAT_YUV422: | ||
569 | return WIN_COLOR_DEPTH_YCbCr422P; | ||
570 | |||
571 | default: | ||
572 | break; | ||
573 | } | ||
574 | |||
575 | WARN(1, "unsupported pixel format %u, using default\n", format); | ||
576 | return WIN_COLOR_DEPTH_B8G8R8A8; | ||
577 | } | ||
578 | |||
579 | static int tegra_crtc_mode_set(struct drm_crtc *crtc, | ||
580 | struct drm_display_mode *mode, | ||
581 | struct drm_display_mode *adjusted, | ||
582 | int x, int y, struct drm_framebuffer *old_fb) | ||
583 | { | ||
584 | struct tegra_bo *bo = tegra_fb_get_plane(crtc->fb, 0); | ||
585 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
586 | struct tegra_dc_window window; | ||
587 | unsigned long div, value; | ||
588 | int err; | ||
589 | |||
590 | drm_vblank_pre_modeset(crtc->dev, dc->pipe); | ||
591 | |||
592 | err = tegra_crtc_setup_clk(crtc, mode, &div); | ||
593 | if (err) { | ||
594 | dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err); | ||
595 | return err; | ||
596 | } | ||
597 | |||
598 | /* program display mode */ | ||
599 | tegra_dc_set_timings(dc, mode); | ||
600 | |||
601 | value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL; | ||
602 | tegra_dc_writel(dc, value, DC_DISP_DATA_ENABLE_OPTIONS); | ||
603 | |||
604 | value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY(1)); | ||
605 | value &= ~LVS_OUTPUT_POLARITY_LOW; | ||
606 | value &= ~LHS_OUTPUT_POLARITY_LOW; | ||
607 | tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_POLARITY(1)); | ||
608 | |||
609 | value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB | | ||
610 | DISP_ORDER_RED_BLUE; | ||
611 | tegra_dc_writel(dc, value, DC_DISP_DISP_INTERFACE_CONTROL); | ||
612 | |||
613 | tegra_dc_writel(dc, 0x00010001, DC_DISP_SHIFT_CLOCK_OPTIONS); | ||
614 | |||
615 | value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1; | ||
616 | tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); | ||
617 | |||
618 | /* setup window parameters */ | ||
619 | memset(&window, 0, sizeof(window)); | ||
620 | window.src.x = 0; | ||
621 | window.src.y = 0; | ||
622 | window.src.w = mode->hdisplay; | ||
623 | window.src.h = mode->vdisplay; | ||
624 | window.dst.x = 0; | ||
625 | window.dst.y = 0; | ||
626 | window.dst.w = mode->hdisplay; | ||
627 | window.dst.h = mode->vdisplay; | ||
628 | window.format = tegra_dc_format(crtc->fb->pixel_format); | ||
629 | window.bits_per_pixel = crtc->fb->bits_per_pixel; | ||
630 | window.stride[0] = crtc->fb->pitches[0]; | ||
631 | window.base[0] = bo->paddr; | ||
632 | |||
633 | err = tegra_dc_setup_window(dc, 0, &window); | ||
634 | if (err < 0) | ||
635 | dev_err(dc->dev, "failed to enable root plane\n"); | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | ||
641 | struct drm_framebuffer *old_fb) | ||
642 | { | ||
643 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
644 | |||
645 | return tegra_dc_set_base(dc, x, y, crtc->fb); | ||
646 | } | ||
647 | |||
648 | static void tegra_crtc_prepare(struct drm_crtc *crtc) | ||
649 | { | ||
650 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
651 | unsigned int syncpt; | ||
652 | unsigned long value; | ||
653 | |||
654 | /* hardware initialization */ | ||
655 | tegra_periph_reset_deassert(dc->clk); | ||
656 | usleep_range(10000, 20000); | ||
657 | |||
658 | if (dc->pipe) | ||
659 | syncpt = SYNCPT_VBLANK1; | ||
660 | else | ||
661 | syncpt = SYNCPT_VBLANK0; | ||
662 | |||
663 | /* initialize display controller */ | ||
664 | tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); | ||
665 | tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC); | ||
666 | |||
667 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT; | ||
668 | tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); | ||
669 | |||
670 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
671 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
672 | tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY); | ||
673 | |||
674 | value = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | | ||
675 | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; | ||
676 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); | ||
677 | |||
678 | value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); | ||
679 | value |= DISP_CTRL_MODE_C_DISPLAY; | ||
680 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); | ||
681 | |||
682 | /* initialize timer */ | ||
683 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | | ||
684 | WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); | ||
685 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY); | ||
686 | |||
687 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) | | ||
688 | WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1); | ||
689 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); | ||
690 | |||
691 | value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; | ||
692 | tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); | ||
693 | |||
694 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; | ||
695 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
696 | } | ||
697 | |||
698 | static void tegra_crtc_commit(struct drm_crtc *crtc) | ||
699 | { | ||
700 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
701 | unsigned long value; | ||
702 | |||
703 | value = GENERAL_UPDATE | WIN_A_UPDATE; | ||
704 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
705 | |||
706 | value = GENERAL_ACT_REQ | WIN_A_ACT_REQ; | ||
707 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
708 | |||
709 | drm_vblank_post_modeset(crtc->dev, dc->pipe); | ||
710 | } | ||
711 | |||
712 | static void tegra_crtc_load_lut(struct drm_crtc *crtc) | ||
713 | { | ||
714 | } | ||
715 | |||
716 | static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { | ||
717 | .disable = tegra_crtc_disable, | ||
718 | .mode_fixup = tegra_crtc_mode_fixup, | ||
719 | .mode_set = tegra_crtc_mode_set, | ||
720 | .mode_set_base = tegra_crtc_mode_set_base, | ||
721 | .prepare = tegra_crtc_prepare, | ||
722 | .commit = tegra_crtc_commit, | ||
723 | .load_lut = tegra_crtc_load_lut, | ||
724 | }; | ||
725 | |||
726 | static irqreturn_t tegra_dc_irq(int irq, void *data) | ||
727 | { | ||
728 | struct tegra_dc *dc = data; | ||
729 | unsigned long status; | ||
730 | |||
731 | status = tegra_dc_readl(dc, DC_CMD_INT_STATUS); | ||
732 | tegra_dc_writel(dc, status, DC_CMD_INT_STATUS); | ||
733 | |||
734 | if (status & FRAME_END_INT) { | ||
735 | /* | ||
736 | dev_dbg(dc->dev, "%s(): frame end\n", __func__); | ||
737 | */ | ||
738 | } | ||
739 | |||
740 | if (status & VBLANK_INT) { | ||
741 | /* | ||
742 | dev_dbg(dc->dev, "%s(): vertical blank\n", __func__); | ||
743 | */ | ||
744 | drm_handle_vblank(dc->base.dev, dc->pipe); | ||
745 | tegra_dc_finish_page_flip(dc); | ||
746 | } | ||
747 | |||
748 | if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) { | ||
749 | /* | ||
750 | dev_dbg(dc->dev, "%s(): underflow\n", __func__); | ||
751 | */ | ||
752 | } | ||
753 | |||
754 | return IRQ_HANDLED; | ||
755 | } | ||
756 | |||
757 | static int tegra_dc_show_regs(struct seq_file *s, void *data) | ||
758 | { | ||
759 | struct drm_info_node *node = s->private; | ||
760 | struct tegra_dc *dc = node->info_ent->data; | ||
761 | |||
762 | #define DUMP_REG(name) \ | ||
763 | seq_printf(s, "%-40s %#05x %08lx\n", #name, name, \ | ||
764 | tegra_dc_readl(dc, name)) | ||
765 | |||
766 | DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT); | ||
767 | DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); | ||
768 | DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_ERROR); | ||
769 | DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT); | ||
770 | DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL); | ||
771 | DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_ERROR); | ||
772 | DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT); | ||
773 | DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL); | ||
774 | DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_ERROR); | ||
775 | DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT); | ||
776 | DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL); | ||
777 | DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_ERROR); | ||
778 | DUMP_REG(DC_CMD_CONT_SYNCPT_VSYNC); | ||
779 | DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0); | ||
780 | DUMP_REG(DC_CMD_DISPLAY_COMMAND); | ||
781 | DUMP_REG(DC_CMD_SIGNAL_RAISE); | ||
782 | DUMP_REG(DC_CMD_DISPLAY_POWER_CONTROL); | ||
783 | DUMP_REG(DC_CMD_INT_STATUS); | ||
784 | DUMP_REG(DC_CMD_INT_MASK); | ||
785 | DUMP_REG(DC_CMD_INT_ENABLE); | ||
786 | DUMP_REG(DC_CMD_INT_TYPE); | ||
787 | DUMP_REG(DC_CMD_INT_POLARITY); | ||
788 | DUMP_REG(DC_CMD_SIGNAL_RAISE1); | ||
789 | DUMP_REG(DC_CMD_SIGNAL_RAISE2); | ||
790 | DUMP_REG(DC_CMD_SIGNAL_RAISE3); | ||
791 | DUMP_REG(DC_CMD_STATE_ACCESS); | ||
792 | DUMP_REG(DC_CMD_STATE_CONTROL); | ||
793 | DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER); | ||
794 | DUMP_REG(DC_CMD_REG_ACT_CONTROL); | ||
795 | DUMP_REG(DC_COM_CRC_CONTROL); | ||
796 | DUMP_REG(DC_COM_CRC_CHECKSUM); | ||
797 | DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(0)); | ||
798 | DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(1)); | ||
799 | DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(2)); | ||
800 | DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(3)); | ||
801 | DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(0)); | ||
802 | DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(1)); | ||
803 | DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(2)); | ||
804 | DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(3)); | ||
805 | DUMP_REG(DC_COM_PIN_OUTPUT_DATA(0)); | ||
806 | DUMP_REG(DC_COM_PIN_OUTPUT_DATA(1)); | ||
807 | DUMP_REG(DC_COM_PIN_OUTPUT_DATA(2)); | ||
808 | DUMP_REG(DC_COM_PIN_OUTPUT_DATA(3)); | ||
809 | DUMP_REG(DC_COM_PIN_INPUT_ENABLE(0)); | ||
810 | DUMP_REG(DC_COM_PIN_INPUT_ENABLE(1)); | ||
811 | DUMP_REG(DC_COM_PIN_INPUT_ENABLE(2)); | ||
812 | DUMP_REG(DC_COM_PIN_INPUT_ENABLE(3)); | ||
813 | DUMP_REG(DC_COM_PIN_INPUT_DATA(0)); | ||
814 | DUMP_REG(DC_COM_PIN_INPUT_DATA(1)); | ||
815 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(0)); | ||
816 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(1)); | ||
817 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(2)); | ||
818 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(3)); | ||
819 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(4)); | ||
820 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(5)); | ||
821 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(6)); | ||
822 | DUMP_REG(DC_COM_PIN_MISC_CONTROL); | ||
823 | DUMP_REG(DC_COM_PIN_PM0_CONTROL); | ||
824 | DUMP_REG(DC_COM_PIN_PM0_DUTY_CYCLE); | ||
825 | DUMP_REG(DC_COM_PIN_PM1_CONTROL); | ||
826 | DUMP_REG(DC_COM_PIN_PM1_DUTY_CYCLE); | ||
827 | DUMP_REG(DC_COM_SPI_CONTROL); | ||
828 | DUMP_REG(DC_COM_SPI_START_BYTE); | ||
829 | DUMP_REG(DC_COM_HSPI_WRITE_DATA_AB); | ||
830 | DUMP_REG(DC_COM_HSPI_WRITE_DATA_CD); | ||
831 | DUMP_REG(DC_COM_HSPI_CS_DC); | ||
832 | DUMP_REG(DC_COM_SCRATCH_REGISTER_A); | ||
833 | DUMP_REG(DC_COM_SCRATCH_REGISTER_B); | ||
834 | DUMP_REG(DC_COM_GPIO_CTRL); | ||
835 | DUMP_REG(DC_COM_GPIO_DEBOUNCE_COUNTER); | ||
836 | DUMP_REG(DC_COM_CRC_CHECKSUM_LATCHED); | ||
837 | DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0); | ||
838 | DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1); | ||
839 | DUMP_REG(DC_DISP_DISP_WIN_OPTIONS); | ||
840 | DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY); | ||
841 | DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); | ||
842 | DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS); | ||
843 | DUMP_REG(DC_DISP_REF_TO_SYNC); | ||
844 | DUMP_REG(DC_DISP_SYNC_WIDTH); | ||
845 | DUMP_REG(DC_DISP_BACK_PORCH); | ||
846 | DUMP_REG(DC_DISP_ACTIVE); | ||
847 | DUMP_REG(DC_DISP_FRONT_PORCH); | ||
848 | DUMP_REG(DC_DISP_H_PULSE0_CONTROL); | ||
849 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_A); | ||
850 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_B); | ||
851 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_C); | ||
852 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_D); | ||
853 | DUMP_REG(DC_DISP_H_PULSE1_CONTROL); | ||
854 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_A); | ||
855 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_B); | ||
856 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_C); | ||
857 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_D); | ||
858 | DUMP_REG(DC_DISP_H_PULSE2_CONTROL); | ||
859 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_A); | ||
860 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_B); | ||
861 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_C); | ||
862 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_D); | ||
863 | DUMP_REG(DC_DISP_V_PULSE0_CONTROL); | ||
864 | DUMP_REG(DC_DISP_V_PULSE0_POSITION_A); | ||
865 | DUMP_REG(DC_DISP_V_PULSE0_POSITION_B); | ||
866 | DUMP_REG(DC_DISP_V_PULSE0_POSITION_C); | ||
867 | DUMP_REG(DC_DISP_V_PULSE1_CONTROL); | ||
868 | DUMP_REG(DC_DISP_V_PULSE1_POSITION_A); | ||
869 | DUMP_REG(DC_DISP_V_PULSE1_POSITION_B); | ||
870 | DUMP_REG(DC_DISP_V_PULSE1_POSITION_C); | ||
871 | DUMP_REG(DC_DISP_V_PULSE2_CONTROL); | ||
872 | DUMP_REG(DC_DISP_V_PULSE2_POSITION_A); | ||
873 | DUMP_REG(DC_DISP_V_PULSE3_CONTROL); | ||
874 | DUMP_REG(DC_DISP_V_PULSE3_POSITION_A); | ||
875 | DUMP_REG(DC_DISP_M0_CONTROL); | ||
876 | DUMP_REG(DC_DISP_M1_CONTROL); | ||
877 | DUMP_REG(DC_DISP_DI_CONTROL); | ||
878 | DUMP_REG(DC_DISP_PP_CONTROL); | ||
879 | DUMP_REG(DC_DISP_PP_SELECT_A); | ||
880 | DUMP_REG(DC_DISP_PP_SELECT_B); | ||
881 | DUMP_REG(DC_DISP_PP_SELECT_C); | ||
882 | DUMP_REG(DC_DISP_PP_SELECT_D); | ||
883 | DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL); | ||
884 | DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL); | ||
885 | DUMP_REG(DC_DISP_DISP_COLOR_CONTROL); | ||
886 | DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS); | ||
887 | DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS); | ||
888 | DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS); | ||
889 | DUMP_REG(DC_DISP_LCD_SPI_OPTIONS); | ||
890 | DUMP_REG(DC_DISP_BORDER_COLOR); | ||
891 | DUMP_REG(DC_DISP_COLOR_KEY0_LOWER); | ||
892 | DUMP_REG(DC_DISP_COLOR_KEY0_UPPER); | ||
893 | DUMP_REG(DC_DISP_COLOR_KEY1_LOWER); | ||
894 | DUMP_REG(DC_DISP_COLOR_KEY1_UPPER); | ||
895 | DUMP_REG(DC_DISP_CURSOR_FOREGROUND); | ||
896 | DUMP_REG(DC_DISP_CURSOR_BACKGROUND); | ||
897 | DUMP_REG(DC_DISP_CURSOR_START_ADDR); | ||
898 | DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS); | ||
899 | DUMP_REG(DC_DISP_CURSOR_POSITION); | ||
900 | DUMP_REG(DC_DISP_CURSOR_POSITION_NS); | ||
901 | DUMP_REG(DC_DISP_INIT_SEQ_CONTROL); | ||
902 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A); | ||
903 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B); | ||
904 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C); | ||
905 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D); | ||
906 | DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL); | ||
907 | DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST); | ||
908 | DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST); | ||
909 | DUMP_REG(DC_DISP_MCCIF_DISPLAY1A_HYST); | ||
910 | DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST); | ||
911 | DUMP_REG(DC_DISP_DAC_CRT_CTRL); | ||
912 | DUMP_REG(DC_DISP_DISP_MISC_CONTROL); | ||
913 | DUMP_REG(DC_DISP_SD_CONTROL); | ||
914 | DUMP_REG(DC_DISP_SD_CSC_COEFF); | ||
915 | DUMP_REG(DC_DISP_SD_LUT(0)); | ||
916 | DUMP_REG(DC_DISP_SD_LUT(1)); | ||
917 | DUMP_REG(DC_DISP_SD_LUT(2)); | ||
918 | DUMP_REG(DC_DISP_SD_LUT(3)); | ||
919 | DUMP_REG(DC_DISP_SD_LUT(4)); | ||
920 | DUMP_REG(DC_DISP_SD_LUT(5)); | ||
921 | DUMP_REG(DC_DISP_SD_LUT(6)); | ||
922 | DUMP_REG(DC_DISP_SD_LUT(7)); | ||
923 | DUMP_REG(DC_DISP_SD_LUT(8)); | ||
924 | DUMP_REG(DC_DISP_SD_FLICKER_CONTROL); | ||
925 | DUMP_REG(DC_DISP_DC_PIXEL_COUNT); | ||
926 | DUMP_REG(DC_DISP_SD_HISTOGRAM(0)); | ||
927 | DUMP_REG(DC_DISP_SD_HISTOGRAM(1)); | ||
928 | DUMP_REG(DC_DISP_SD_HISTOGRAM(2)); | ||
929 | DUMP_REG(DC_DISP_SD_HISTOGRAM(3)); | ||
930 | DUMP_REG(DC_DISP_SD_HISTOGRAM(4)); | ||
931 | DUMP_REG(DC_DISP_SD_HISTOGRAM(5)); | ||
932 | DUMP_REG(DC_DISP_SD_HISTOGRAM(6)); | ||
933 | DUMP_REG(DC_DISP_SD_HISTOGRAM(7)); | ||
934 | DUMP_REG(DC_DISP_SD_BL_TF(0)); | ||
935 | DUMP_REG(DC_DISP_SD_BL_TF(1)); | ||
936 | DUMP_REG(DC_DISP_SD_BL_TF(2)); | ||
937 | DUMP_REG(DC_DISP_SD_BL_TF(3)); | ||
938 | DUMP_REG(DC_DISP_SD_BL_CONTROL); | ||
939 | DUMP_REG(DC_DISP_SD_HW_K_VALUES); | ||
940 | DUMP_REG(DC_DISP_SD_MAN_K_VALUES); | ||
941 | DUMP_REG(DC_WIN_WIN_OPTIONS); | ||
942 | DUMP_REG(DC_WIN_BYTE_SWAP); | ||
943 | DUMP_REG(DC_WIN_BUFFER_CONTROL); | ||
944 | DUMP_REG(DC_WIN_COLOR_DEPTH); | ||
945 | DUMP_REG(DC_WIN_POSITION); | ||
946 | DUMP_REG(DC_WIN_SIZE); | ||
947 | DUMP_REG(DC_WIN_PRESCALED_SIZE); | ||
948 | DUMP_REG(DC_WIN_H_INITIAL_DDA); | ||
949 | DUMP_REG(DC_WIN_V_INITIAL_DDA); | ||
950 | DUMP_REG(DC_WIN_DDA_INC); | ||
951 | DUMP_REG(DC_WIN_LINE_STRIDE); | ||
952 | DUMP_REG(DC_WIN_BUF_STRIDE); | ||
953 | DUMP_REG(DC_WIN_UV_BUF_STRIDE); | ||
954 | DUMP_REG(DC_WIN_BUFFER_ADDR_MODE); | ||
955 | DUMP_REG(DC_WIN_DV_CONTROL); | ||
956 | DUMP_REG(DC_WIN_BLEND_NOKEY); | ||
957 | DUMP_REG(DC_WIN_BLEND_1WIN); | ||
958 | DUMP_REG(DC_WIN_BLEND_2WIN_X); | ||
959 | DUMP_REG(DC_WIN_BLEND_2WIN_Y); | ||
960 | DUMP_REG(DC_WIN_BLEND_3WIN_XY); | ||
961 | DUMP_REG(DC_WIN_HP_FETCH_CONTROL); | ||
962 | DUMP_REG(DC_WINBUF_START_ADDR); | ||
963 | DUMP_REG(DC_WINBUF_START_ADDR_NS); | ||
964 | DUMP_REG(DC_WINBUF_START_ADDR_U); | ||
965 | DUMP_REG(DC_WINBUF_START_ADDR_U_NS); | ||
966 | DUMP_REG(DC_WINBUF_START_ADDR_V); | ||
967 | DUMP_REG(DC_WINBUF_START_ADDR_V_NS); | ||
968 | DUMP_REG(DC_WINBUF_ADDR_H_OFFSET); | ||
969 | DUMP_REG(DC_WINBUF_ADDR_H_OFFSET_NS); | ||
970 | DUMP_REG(DC_WINBUF_ADDR_V_OFFSET); | ||
971 | DUMP_REG(DC_WINBUF_ADDR_V_OFFSET_NS); | ||
972 | DUMP_REG(DC_WINBUF_UFLOW_STATUS); | ||
973 | DUMP_REG(DC_WINBUF_AD_UFLOW_STATUS); | ||
974 | DUMP_REG(DC_WINBUF_BD_UFLOW_STATUS); | ||
975 | DUMP_REG(DC_WINBUF_CD_UFLOW_STATUS); | ||
976 | |||
977 | #undef DUMP_REG | ||
978 | |||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | static struct drm_info_list debugfs_files[] = { | ||
983 | { "regs", tegra_dc_show_regs, 0, NULL }, | ||
984 | }; | ||
985 | |||
986 | static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor) | ||
987 | { | ||
988 | unsigned int i; | ||
989 | char *name; | ||
990 | int err; | ||
991 | |||
992 | name = kasprintf(GFP_KERNEL, "dc.%d", dc->pipe); | ||
993 | dc->debugfs = debugfs_create_dir(name, minor->debugfs_root); | ||
994 | kfree(name); | ||
995 | |||
996 | if (!dc->debugfs) | ||
997 | return -ENOMEM; | ||
998 | |||
999 | dc->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), | ||
1000 | GFP_KERNEL); | ||
1001 | if (!dc->debugfs_files) { | ||
1002 | err = -ENOMEM; | ||
1003 | goto remove; | ||
1004 | } | ||
1005 | |||
1006 | for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) | ||
1007 | dc->debugfs_files[i].data = dc; | ||
1008 | |||
1009 | err = drm_debugfs_create_files(dc->debugfs_files, | ||
1010 | ARRAY_SIZE(debugfs_files), | ||
1011 | dc->debugfs, minor); | ||
1012 | if (err < 0) | ||
1013 | goto free; | ||
1014 | |||
1015 | dc->minor = minor; | ||
1016 | |||
1017 | return 0; | ||
1018 | |||
1019 | free: | ||
1020 | kfree(dc->debugfs_files); | ||
1021 | dc->debugfs_files = NULL; | ||
1022 | remove: | ||
1023 | debugfs_remove(dc->debugfs); | ||
1024 | dc->debugfs = NULL; | ||
1025 | |||
1026 | return err; | ||
1027 | } | ||
1028 | |||
1029 | static int tegra_dc_debugfs_exit(struct tegra_dc *dc) | ||
1030 | { | ||
1031 | drm_debugfs_remove_files(dc->debugfs_files, ARRAY_SIZE(debugfs_files), | ||
1032 | dc->minor); | ||
1033 | dc->minor = NULL; | ||
1034 | |||
1035 | kfree(dc->debugfs_files); | ||
1036 | dc->debugfs_files = NULL; | ||
1037 | |||
1038 | debugfs_remove(dc->debugfs); | ||
1039 | dc->debugfs = NULL; | ||
1040 | |||
1041 | return 0; | ||
1042 | } | ||
1043 | |||
1044 | static int tegra_dc_drm_init(struct host1x_client *client, | ||
1045 | struct drm_device *drm) | ||
1046 | { | ||
1047 | struct tegra_dc *dc = host1x_client_to_dc(client); | ||
1048 | int err; | ||
1049 | |||
1050 | dc->pipe = drm->mode_config.num_crtc; | ||
1051 | |||
1052 | drm_crtc_init(drm, &dc->base, &tegra_crtc_funcs); | ||
1053 | drm_mode_crtc_set_gamma_size(&dc->base, 256); | ||
1054 | drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); | ||
1055 | |||
1056 | err = tegra_dc_rgb_init(drm, dc); | ||
1057 | if (err < 0 && err != -ENODEV) { | ||
1058 | dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); | ||
1059 | return err; | ||
1060 | } | ||
1061 | |||
1062 | err = tegra_dc_add_planes(drm, dc); | ||
1063 | if (err < 0) | ||
1064 | return err; | ||
1065 | |||
1066 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
1067 | err = tegra_dc_debugfs_init(dc, drm->primary); | ||
1068 | if (err < 0) | ||
1069 | dev_err(dc->dev, "debugfs setup failed: %d\n", err); | ||
1070 | } | ||
1071 | |||
1072 | err = devm_request_irq(dc->dev, dc->irq, tegra_dc_irq, 0, | ||
1073 | dev_name(dc->dev), dc); | ||
1074 | if (err < 0) { | ||
1075 | dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, | ||
1076 | err); | ||
1077 | return err; | ||
1078 | } | ||
1079 | |||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | static int tegra_dc_drm_exit(struct host1x_client *client) | ||
1084 | { | ||
1085 | struct tegra_dc *dc = host1x_client_to_dc(client); | ||
1086 | int err; | ||
1087 | |||
1088 | devm_free_irq(dc->dev, dc->irq, dc); | ||
1089 | |||
1090 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
1091 | err = tegra_dc_debugfs_exit(dc); | ||
1092 | if (err < 0) | ||
1093 | dev_err(dc->dev, "debugfs cleanup failed: %d\n", err); | ||
1094 | } | ||
1095 | |||
1096 | err = tegra_dc_rgb_exit(dc); | ||
1097 | if (err) { | ||
1098 | dev_err(dc->dev, "failed to shutdown RGB output: %d\n", err); | ||
1099 | return err; | ||
1100 | } | ||
1101 | |||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1105 | static const struct host1x_client_ops dc_client_ops = { | ||
1106 | .drm_init = tegra_dc_drm_init, | ||
1107 | .drm_exit = tegra_dc_drm_exit, | ||
1108 | }; | ||
1109 | |||
1110 | static int tegra_dc_probe(struct platform_device *pdev) | ||
1111 | { | ||
1112 | struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent); | ||
1113 | struct resource *regs; | ||
1114 | struct tegra_dc *dc; | ||
1115 | int err; | ||
1116 | |||
1117 | dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL); | ||
1118 | if (!dc) | ||
1119 | return -ENOMEM; | ||
1120 | |||
1121 | spin_lock_init(&dc->lock); | ||
1122 | INIT_LIST_HEAD(&dc->list); | ||
1123 | dc->dev = &pdev->dev; | ||
1124 | |||
1125 | dc->clk = devm_clk_get(&pdev->dev, NULL); | ||
1126 | if (IS_ERR(dc->clk)) { | ||
1127 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
1128 | return PTR_ERR(dc->clk); | ||
1129 | } | ||
1130 | |||
1131 | err = clk_prepare_enable(dc->clk); | ||
1132 | if (err < 0) | ||
1133 | return err; | ||
1134 | |||
1135 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1136 | dc->regs = devm_ioremap_resource(&pdev->dev, regs); | ||
1137 | if (IS_ERR(dc->regs)) | ||
1138 | return PTR_ERR(dc->regs); | ||
1139 | |||
1140 | dc->irq = platform_get_irq(pdev, 0); | ||
1141 | if (dc->irq < 0) { | ||
1142 | dev_err(&pdev->dev, "failed to get IRQ\n"); | ||
1143 | return -ENXIO; | ||
1144 | } | ||
1145 | |||
1146 | INIT_LIST_HEAD(&dc->client.list); | ||
1147 | dc->client.ops = &dc_client_ops; | ||
1148 | dc->client.dev = &pdev->dev; | ||
1149 | |||
1150 | err = tegra_dc_rgb_probe(dc); | ||
1151 | if (err < 0 && err != -ENODEV) { | ||
1152 | dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err); | ||
1153 | return err; | ||
1154 | } | ||
1155 | |||
1156 | err = host1x_register_client(host1x, &dc->client); | ||
1157 | if (err < 0) { | ||
1158 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", | ||
1159 | err); | ||
1160 | return err; | ||
1161 | } | ||
1162 | |||
1163 | platform_set_drvdata(pdev, dc); | ||
1164 | |||
1165 | return 0; | ||
1166 | } | ||
1167 | |||
1168 | static int tegra_dc_remove(struct platform_device *pdev) | ||
1169 | { | ||
1170 | struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent); | ||
1171 | struct tegra_dc *dc = platform_get_drvdata(pdev); | ||
1172 | int err; | ||
1173 | |||
1174 | err = host1x_unregister_client(host1x, &dc->client); | ||
1175 | if (err < 0) { | ||
1176 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", | ||
1177 | err); | ||
1178 | return err; | ||
1179 | } | ||
1180 | |||
1181 | clk_disable_unprepare(dc->clk); | ||
1182 | |||
1183 | return 0; | ||
1184 | } | ||
1185 | |||
1186 | static struct of_device_id tegra_dc_of_match[] = { | ||
1187 | { .compatible = "nvidia,tegra30-dc", }, | ||
1188 | { .compatible = "nvidia,tegra20-dc", }, | ||
1189 | { }, | ||
1190 | }; | ||
1191 | |||
1192 | struct platform_driver tegra_dc_driver = { | ||
1193 | .driver = { | ||
1194 | .name = "tegra-dc", | ||
1195 | .owner = THIS_MODULE, | ||
1196 | .of_match_table = tegra_dc_of_match, | ||
1197 | }, | ||
1198 | .probe = tegra_dc_probe, | ||
1199 | .remove = tegra_dc_remove, | ||
1200 | }; | ||
diff --git a/drivers/gpu/host1x/drm/dc.h b/drivers/gpu/host1x/drm/dc.h deleted file mode 100644 index 79eaec9aac77..000000000000 --- a/drivers/gpu/host1x/drm/dc.h +++ /dev/null | |||
@@ -1,400 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Avionic Design GmbH | ||
3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #ifndef TEGRA_DC_H | ||
11 | #define TEGRA_DC_H 1 | ||
12 | |||
13 | #define DC_CMD_GENERAL_INCR_SYNCPT 0x000 | ||
14 | #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001 | ||
15 | #define DC_CMD_GENERAL_INCR_SYNCPT_ERROR 0x002 | ||
16 | #define DC_CMD_WIN_A_INCR_SYNCPT 0x008 | ||
17 | #define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL 0x009 | ||
18 | #define DC_CMD_WIN_A_INCR_SYNCPT_ERROR 0x00a | ||
19 | #define DC_CMD_WIN_B_INCR_SYNCPT 0x010 | ||
20 | #define DC_CMD_WIN_B_INCR_SYNCPT_CNTRL 0x011 | ||
21 | #define DC_CMD_WIN_B_INCR_SYNCPT_ERROR 0x012 | ||
22 | #define DC_CMD_WIN_C_INCR_SYNCPT 0x018 | ||
23 | #define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL 0x019 | ||
24 | #define DC_CMD_WIN_C_INCR_SYNCPT_ERROR 0x01a | ||
25 | #define DC_CMD_CONT_SYNCPT_VSYNC 0x028 | ||
26 | #define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 | ||
27 | #define DC_CMD_DISPLAY_COMMAND 0x032 | ||
28 | #define DISP_CTRL_MODE_STOP (0 << 5) | ||
29 | #define DISP_CTRL_MODE_C_DISPLAY (1 << 5) | ||
30 | #define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) | ||
31 | #define DC_CMD_SIGNAL_RAISE 0x033 | ||
32 | #define DC_CMD_DISPLAY_POWER_CONTROL 0x036 | ||
33 | #define PW0_ENABLE (1 << 0) | ||
34 | #define PW1_ENABLE (1 << 2) | ||
35 | #define PW2_ENABLE (1 << 4) | ||
36 | #define PW3_ENABLE (1 << 6) | ||
37 | #define PW4_ENABLE (1 << 8) | ||
38 | #define PM0_ENABLE (1 << 16) | ||
39 | #define PM1_ENABLE (1 << 18) | ||
40 | |||
41 | #define DC_CMD_INT_STATUS 0x037 | ||
42 | #define DC_CMD_INT_MASK 0x038 | ||
43 | #define DC_CMD_INT_ENABLE 0x039 | ||
44 | #define DC_CMD_INT_TYPE 0x03a | ||
45 | #define DC_CMD_INT_POLARITY 0x03b | ||
46 | #define CTXSW_INT (1 << 0) | ||
47 | #define FRAME_END_INT (1 << 1) | ||
48 | #define VBLANK_INT (1 << 2) | ||
49 | #define WIN_A_UF_INT (1 << 8) | ||
50 | #define WIN_B_UF_INT (1 << 9) | ||
51 | #define WIN_C_UF_INT (1 << 10) | ||
52 | #define WIN_A_OF_INT (1 << 14) | ||
53 | #define WIN_B_OF_INT (1 << 15) | ||
54 | #define WIN_C_OF_INT (1 << 16) | ||
55 | |||
56 | #define DC_CMD_SIGNAL_RAISE1 0x03c | ||
57 | #define DC_CMD_SIGNAL_RAISE2 0x03d | ||
58 | #define DC_CMD_SIGNAL_RAISE3 0x03e | ||
59 | |||
60 | #define DC_CMD_STATE_ACCESS 0x040 | ||
61 | #define READ_MUX (1 << 0) | ||
62 | #define WRITE_MUX (1 << 2) | ||
63 | |||
64 | #define DC_CMD_STATE_CONTROL 0x041 | ||
65 | #define GENERAL_ACT_REQ (1 << 0) | ||
66 | #define WIN_A_ACT_REQ (1 << 1) | ||
67 | #define WIN_B_ACT_REQ (1 << 2) | ||
68 | #define WIN_C_ACT_REQ (1 << 3) | ||
69 | #define GENERAL_UPDATE (1 << 8) | ||
70 | #define WIN_A_UPDATE (1 << 9) | ||
71 | #define WIN_B_UPDATE (1 << 10) | ||
72 | #define WIN_C_UPDATE (1 << 11) | ||
73 | #define NC_HOST_TRIG (1 << 24) | ||
74 | |||
75 | #define DC_CMD_DISPLAY_WINDOW_HEADER 0x042 | ||
76 | #define WINDOW_A_SELECT (1 << 4) | ||
77 | #define WINDOW_B_SELECT (1 << 5) | ||
78 | #define WINDOW_C_SELECT (1 << 6) | ||
79 | |||
80 | #define DC_CMD_REG_ACT_CONTROL 0x043 | ||
81 | |||
82 | #define DC_COM_CRC_CONTROL 0x300 | ||
83 | #define DC_COM_CRC_CHECKSUM 0x301 | ||
84 | #define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x)) | ||
85 | #define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) | ||
86 | #define LVS_OUTPUT_POLARITY_LOW (1 << 28) | ||
87 | #define LHS_OUTPUT_POLARITY_LOW (1 << 30) | ||
88 | #define DC_COM_PIN_OUTPUT_DATA(x) (0x30a + (x)) | ||
89 | #define DC_COM_PIN_INPUT_ENABLE(x) (0x30e + (x)) | ||
90 | #define DC_COM_PIN_INPUT_DATA(x) (0x312 + (x)) | ||
91 | #define DC_COM_PIN_OUTPUT_SELECT(x) (0x314 + (x)) | ||
92 | |||
93 | #define DC_COM_PIN_MISC_CONTROL 0x31b | ||
94 | #define DC_COM_PIN_PM0_CONTROL 0x31c | ||
95 | #define DC_COM_PIN_PM0_DUTY_CYCLE 0x31d | ||
96 | #define DC_COM_PIN_PM1_CONTROL 0x31e | ||
97 | #define DC_COM_PIN_PM1_DUTY_CYCLE 0x31f | ||
98 | |||
99 | #define DC_COM_SPI_CONTROL 0x320 | ||
100 | #define DC_COM_SPI_START_BYTE 0x321 | ||
101 | #define DC_COM_HSPI_WRITE_DATA_AB 0x322 | ||
102 | #define DC_COM_HSPI_WRITE_DATA_CD 0x323 | ||
103 | #define DC_COM_HSPI_CS_DC 0x324 | ||
104 | #define DC_COM_SCRATCH_REGISTER_A 0x325 | ||
105 | #define DC_COM_SCRATCH_REGISTER_B 0x326 | ||
106 | #define DC_COM_GPIO_CTRL 0x327 | ||
107 | #define DC_COM_GPIO_DEBOUNCE_COUNTER 0x328 | ||
108 | #define DC_COM_CRC_CHECKSUM_LATCHED 0x329 | ||
109 | |||
110 | #define DC_DISP_DISP_SIGNAL_OPTIONS0 0x400 | ||
111 | #define H_PULSE_0_ENABLE (1 << 8) | ||
112 | #define H_PULSE_1_ENABLE (1 << 10) | ||
113 | #define H_PULSE_2_ENABLE (1 << 12) | ||
114 | |||
115 | #define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401 | ||
116 | |||
117 | #define DC_DISP_DISP_WIN_OPTIONS 0x402 | ||
118 | #define HDMI_ENABLE (1 << 30) | ||
119 | |||
120 | #define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 | ||
121 | #define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24) | ||
122 | #define WINDOW_A_THRESHOLD(x) (((x) & 0x7f) << 16) | ||
123 | #define WINDOW_B_THRESHOLD(x) (((x) & 0x7f) << 8) | ||
124 | #define WINDOW_C_THRESHOLD(x) (((x) & 0xff) << 0) | ||
125 | |||
126 | #define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 | ||
127 | #define CURSOR_DELAY(x) (((x) & 0x3f) << 24) | ||
128 | #define WINDOW_A_DELAY(x) (((x) & 0x3f) << 16) | ||
129 | #define WINDOW_B_DELAY(x) (((x) & 0x3f) << 8) | ||
130 | #define WINDOW_C_DELAY(x) (((x) & 0x3f) << 0) | ||
131 | |||
132 | #define DC_DISP_DISP_TIMING_OPTIONS 0x405 | ||
133 | #define VSYNC_H_POSITION(x) ((x) & 0xfff) | ||
134 | |||
135 | #define DC_DISP_REF_TO_SYNC 0x406 | ||
136 | #define DC_DISP_SYNC_WIDTH 0x407 | ||
137 | #define DC_DISP_BACK_PORCH 0x408 | ||
138 | #define DC_DISP_ACTIVE 0x409 | ||
139 | #define DC_DISP_FRONT_PORCH 0x40a | ||
140 | #define DC_DISP_H_PULSE0_CONTROL 0x40b | ||
141 | #define DC_DISP_H_PULSE0_POSITION_A 0x40c | ||
142 | #define DC_DISP_H_PULSE0_POSITION_B 0x40d | ||
143 | #define DC_DISP_H_PULSE0_POSITION_C 0x40e | ||
144 | #define DC_DISP_H_PULSE0_POSITION_D 0x40f | ||
145 | #define DC_DISP_H_PULSE1_CONTROL 0x410 | ||
146 | #define DC_DISP_H_PULSE1_POSITION_A 0x411 | ||
147 | #define DC_DISP_H_PULSE1_POSITION_B 0x412 | ||
148 | #define DC_DISP_H_PULSE1_POSITION_C 0x413 | ||
149 | #define DC_DISP_H_PULSE1_POSITION_D 0x414 | ||
150 | #define DC_DISP_H_PULSE2_CONTROL 0x415 | ||
151 | #define DC_DISP_H_PULSE2_POSITION_A 0x416 | ||
152 | #define DC_DISP_H_PULSE2_POSITION_B 0x417 | ||
153 | #define DC_DISP_H_PULSE2_POSITION_C 0x418 | ||
154 | #define DC_DISP_H_PULSE2_POSITION_D 0x419 | ||
155 | #define DC_DISP_V_PULSE0_CONTROL 0x41a | ||
156 | #define DC_DISP_V_PULSE0_POSITION_A 0x41b | ||
157 | #define DC_DISP_V_PULSE0_POSITION_B 0x41c | ||
158 | #define DC_DISP_V_PULSE0_POSITION_C 0x41d | ||
159 | #define DC_DISP_V_PULSE1_CONTROL 0x41e | ||
160 | #define DC_DISP_V_PULSE1_POSITION_A 0x41f | ||
161 | #define DC_DISP_V_PULSE1_POSITION_B 0x420 | ||
162 | #define DC_DISP_V_PULSE1_POSITION_C 0x421 | ||
163 | #define DC_DISP_V_PULSE2_CONTROL 0x422 | ||
164 | #define DC_DISP_V_PULSE2_POSITION_A 0x423 | ||
165 | #define DC_DISP_V_PULSE3_CONTROL 0x424 | ||
166 | #define DC_DISP_V_PULSE3_POSITION_A 0x425 | ||
167 | #define DC_DISP_M0_CONTROL 0x426 | ||
168 | #define DC_DISP_M1_CONTROL 0x427 | ||
169 | #define DC_DISP_DI_CONTROL 0x428 | ||
170 | #define DC_DISP_PP_CONTROL 0x429 | ||
171 | #define DC_DISP_PP_SELECT_A 0x42a | ||
172 | #define DC_DISP_PP_SELECT_B 0x42b | ||
173 | #define DC_DISP_PP_SELECT_C 0x42c | ||
174 | #define DC_DISP_PP_SELECT_D 0x42d | ||
175 | |||
176 | #define PULSE_MODE_NORMAL (0 << 3) | ||
177 | #define PULSE_MODE_ONE_CLOCK (1 << 3) | ||
178 | #define PULSE_POLARITY_HIGH (0 << 4) | ||
179 | #define PULSE_POLARITY_LOW (1 << 4) | ||
180 | #define PULSE_QUAL_ALWAYS (0 << 6) | ||
181 | #define PULSE_QUAL_VACTIVE (2 << 6) | ||
182 | #define PULSE_QUAL_VACTIVE1 (3 << 6) | ||
183 | #define PULSE_LAST_START_A (0 << 8) | ||
184 | #define PULSE_LAST_END_A (1 << 8) | ||
185 | #define PULSE_LAST_START_B (2 << 8) | ||
186 | #define PULSE_LAST_END_B (3 << 8) | ||
187 | #define PULSE_LAST_START_C (4 << 8) | ||
188 | #define PULSE_LAST_END_C (5 << 8) | ||
189 | #define PULSE_LAST_START_D (6 << 8) | ||
190 | #define PULSE_LAST_END_D (7 << 8) | ||
191 | |||
192 | #define PULSE_START(x) (((x) & 0xfff) << 0) | ||
193 | #define PULSE_END(x) (((x) & 0xfff) << 16) | ||
194 | |||
195 | #define DC_DISP_DISP_CLOCK_CONTROL 0x42e | ||
196 | #define PIXEL_CLK_DIVIDER_PCD1 (0 << 8) | ||
197 | #define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) | ||
198 | #define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) | ||
199 | #define PIXEL_CLK_DIVIDER_PCD3 (3 << 8) | ||
200 | #define PIXEL_CLK_DIVIDER_PCD4 (4 << 8) | ||
201 | #define PIXEL_CLK_DIVIDER_PCD6 (5 << 8) | ||
202 | #define PIXEL_CLK_DIVIDER_PCD8 (6 << 8) | ||
203 | #define PIXEL_CLK_DIVIDER_PCD9 (7 << 8) | ||
204 | #define PIXEL_CLK_DIVIDER_PCD12 (8 << 8) | ||
205 | #define PIXEL_CLK_DIVIDER_PCD16 (9 << 8) | ||
206 | #define PIXEL_CLK_DIVIDER_PCD18 (10 << 8) | ||
207 | #define PIXEL_CLK_DIVIDER_PCD24 (11 << 8) | ||
208 | #define PIXEL_CLK_DIVIDER_PCD13 (12 << 8) | ||
209 | #define SHIFT_CLK_DIVIDER(x) ((x) & 0xff) | ||
210 | |||
211 | #define DC_DISP_DISP_INTERFACE_CONTROL 0x42f | ||
212 | #define DISP_DATA_FORMAT_DF1P1C (0 << 0) | ||
213 | #define DISP_DATA_FORMAT_DF1P2C24B (1 << 0) | ||
214 | #define DISP_DATA_FORMAT_DF1P2C18B (2 << 0) | ||
215 | #define DISP_DATA_FORMAT_DF1P2C16B (3 << 0) | ||
216 | #define DISP_DATA_FORMAT_DF2S (4 << 0) | ||
217 | #define DISP_DATA_FORMAT_DF3S (5 << 0) | ||
218 | #define DISP_DATA_FORMAT_DFSPI (6 << 0) | ||
219 | #define DISP_DATA_FORMAT_DF1P3C24B (7 << 0) | ||
220 | #define DISP_DATA_FORMAT_DF1P3C18B (8 << 0) | ||
221 | #define DISP_ALIGNMENT_MSB (0 << 8) | ||
222 | #define DISP_ALIGNMENT_LSB (1 << 8) | ||
223 | #define DISP_ORDER_RED_BLUE (0 << 9) | ||
224 | #define DISP_ORDER_BLUE_RED (1 << 9) | ||
225 | |||
226 | #define DC_DISP_DISP_COLOR_CONTROL 0x430 | ||
227 | #define BASE_COLOR_SIZE666 (0 << 0) | ||
228 | #define BASE_COLOR_SIZE111 (1 << 0) | ||
229 | #define BASE_COLOR_SIZE222 (2 << 0) | ||
230 | #define BASE_COLOR_SIZE333 (3 << 0) | ||
231 | #define BASE_COLOR_SIZE444 (4 << 0) | ||
232 | #define BASE_COLOR_SIZE555 (5 << 0) | ||
233 | #define BASE_COLOR_SIZE565 (6 << 0) | ||
234 | #define BASE_COLOR_SIZE332 (7 << 0) | ||
235 | #define BASE_COLOR_SIZE888 (8 << 0) | ||
236 | #define DITHER_CONTROL_DISABLE (0 << 8) | ||
237 | #define DITHER_CONTROL_ORDERED (2 << 8) | ||
238 | #define DITHER_CONTROL_ERRDIFF (3 << 8) | ||
239 | |||
240 | #define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 | ||
241 | |||
242 | #define DC_DISP_DATA_ENABLE_OPTIONS 0x432 | ||
243 | #define DE_SELECT_ACTIVE_BLANK (0 << 0) | ||
244 | #define DE_SELECT_ACTIVE (1 << 0) | ||
245 | #define DE_SELECT_ACTIVE_IS (2 << 0) | ||
246 | #define DE_CONTROL_ONECLK (0 << 2) | ||
247 | #define DE_CONTROL_NORMAL (1 << 2) | ||
248 | #define DE_CONTROL_EARLY_EXT (2 << 2) | ||
249 | #define DE_CONTROL_EARLY (3 << 2) | ||
250 | #define DE_CONTROL_ACTIVE_BLANK (4 << 2) | ||
251 | |||
252 | #define DC_DISP_SERIAL_INTERFACE_OPTIONS 0x433 | ||
253 | #define DC_DISP_LCD_SPI_OPTIONS 0x434 | ||
254 | #define DC_DISP_BORDER_COLOR 0x435 | ||
255 | #define DC_DISP_COLOR_KEY0_LOWER 0x436 | ||
256 | #define DC_DISP_COLOR_KEY0_UPPER 0x437 | ||
257 | #define DC_DISP_COLOR_KEY1_LOWER 0x438 | ||
258 | #define DC_DISP_COLOR_KEY1_UPPER 0x439 | ||
259 | |||
260 | #define DC_DISP_CURSOR_FOREGROUND 0x43c | ||
261 | #define DC_DISP_CURSOR_BACKGROUND 0x43d | ||
262 | |||
263 | #define DC_DISP_CURSOR_START_ADDR 0x43e | ||
264 | #define DC_DISP_CURSOR_START_ADDR_NS 0x43f | ||
265 | |||
266 | #define DC_DISP_CURSOR_POSITION 0x440 | ||
267 | #define DC_DISP_CURSOR_POSITION_NS 0x441 | ||
268 | |||
269 | #define DC_DISP_INIT_SEQ_CONTROL 0x442 | ||
270 | #define DC_DISP_SPI_INIT_SEQ_DATA_A 0x443 | ||
271 | #define DC_DISP_SPI_INIT_SEQ_DATA_B 0x444 | ||
272 | #define DC_DISP_SPI_INIT_SEQ_DATA_C 0x445 | ||
273 | #define DC_DISP_SPI_INIT_SEQ_DATA_D 0x446 | ||
274 | |||
275 | #define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 | ||
276 | #define DC_DISP_MCCIF_DISPLAY0A_HYST 0x481 | ||
277 | #define DC_DISP_MCCIF_DISPLAY0B_HYST 0x482 | ||
278 | #define DC_DISP_MCCIF_DISPLAY1A_HYST 0x483 | ||
279 | #define DC_DISP_MCCIF_DISPLAY1B_HYST 0x484 | ||
280 | |||
281 | #define DC_DISP_DAC_CRT_CTRL 0x4c0 | ||
282 | #define DC_DISP_DISP_MISC_CONTROL 0x4c1 | ||
283 | #define DC_DISP_SD_CONTROL 0x4c2 | ||
284 | #define DC_DISP_SD_CSC_COEFF 0x4c3 | ||
285 | #define DC_DISP_SD_LUT(x) (0x4c4 + (x)) | ||
286 | #define DC_DISP_SD_FLICKER_CONTROL 0x4cd | ||
287 | #define DC_DISP_DC_PIXEL_COUNT 0x4ce | ||
288 | #define DC_DISP_SD_HISTOGRAM(x) (0x4cf + (x)) | ||
289 | #define DC_DISP_SD_BL_PARAMETERS 0x4d7 | ||
290 | #define DC_DISP_SD_BL_TF(x) (0x4d8 + (x)) | ||
291 | #define DC_DISP_SD_BL_CONTROL 0x4dc | ||
292 | #define DC_DISP_SD_HW_K_VALUES 0x4dd | ||
293 | #define DC_DISP_SD_MAN_K_VALUES 0x4de | ||
294 | |||
295 | #define DC_WIN_CSC_YOF 0x611 | ||
296 | #define DC_WIN_CSC_KYRGB 0x612 | ||
297 | #define DC_WIN_CSC_KUR 0x613 | ||
298 | #define DC_WIN_CSC_KVR 0x614 | ||
299 | #define DC_WIN_CSC_KUG 0x615 | ||
300 | #define DC_WIN_CSC_KVG 0x616 | ||
301 | #define DC_WIN_CSC_KUB 0x617 | ||
302 | #define DC_WIN_CSC_KVB 0x618 | ||
303 | |||
304 | #define DC_WIN_WIN_OPTIONS 0x700 | ||
305 | #define COLOR_EXPAND (1 << 6) | ||
306 | #define CSC_ENABLE (1 << 18) | ||
307 | #define WIN_ENABLE (1 << 30) | ||
308 | |||
309 | #define DC_WIN_BYTE_SWAP 0x701 | ||
310 | #define BYTE_SWAP_NOSWAP (0 << 0) | ||
311 | #define BYTE_SWAP_SWAP2 (1 << 0) | ||
312 | #define BYTE_SWAP_SWAP4 (2 << 0) | ||
313 | #define BYTE_SWAP_SWAP4HW (3 << 0) | ||
314 | |||
315 | #define DC_WIN_BUFFER_CONTROL 0x702 | ||
316 | #define BUFFER_CONTROL_HOST (0 << 0) | ||
317 | #define BUFFER_CONTROL_VI (1 << 0) | ||
318 | #define BUFFER_CONTROL_EPP (2 << 0) | ||
319 | #define BUFFER_CONTROL_MPEGE (3 << 0) | ||
320 | #define BUFFER_CONTROL_SB2D (4 << 0) | ||
321 | |||
322 | #define DC_WIN_COLOR_DEPTH 0x703 | ||
323 | #define WIN_COLOR_DEPTH_P1 0 | ||
324 | #define WIN_COLOR_DEPTH_P2 1 | ||
325 | #define WIN_COLOR_DEPTH_P4 2 | ||
326 | #define WIN_COLOR_DEPTH_P8 3 | ||
327 | #define WIN_COLOR_DEPTH_B4G4R4A4 4 | ||
328 | #define WIN_COLOR_DEPTH_B5G5R5A 5 | ||
329 | #define WIN_COLOR_DEPTH_B5G6R5 6 | ||
330 | #define WIN_COLOR_DEPTH_AB5G5R5 7 | ||
331 | #define WIN_COLOR_DEPTH_B8G8R8A8 12 | ||
332 | #define WIN_COLOR_DEPTH_R8G8B8A8 13 | ||
333 | #define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 14 | ||
334 | #define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 15 | ||
335 | #define WIN_COLOR_DEPTH_YCbCr422 16 | ||
336 | #define WIN_COLOR_DEPTH_YUV422 17 | ||
337 | #define WIN_COLOR_DEPTH_YCbCr420P 18 | ||
338 | #define WIN_COLOR_DEPTH_YUV420P 19 | ||
339 | #define WIN_COLOR_DEPTH_YCbCr422P 20 | ||
340 | #define WIN_COLOR_DEPTH_YUV422P 21 | ||
341 | #define WIN_COLOR_DEPTH_YCbCr422R 22 | ||
342 | #define WIN_COLOR_DEPTH_YUV422R 23 | ||
343 | #define WIN_COLOR_DEPTH_YCbCr422RA 24 | ||
344 | #define WIN_COLOR_DEPTH_YUV422RA 25 | ||
345 | |||
346 | #define DC_WIN_POSITION 0x704 | ||
347 | #define H_POSITION(x) (((x) & 0x1fff) << 0) | ||
348 | #define V_POSITION(x) (((x) & 0x1fff) << 16) | ||
349 | |||
350 | #define DC_WIN_SIZE 0x705 | ||
351 | #define H_SIZE(x) (((x) & 0x1fff) << 0) | ||
352 | #define V_SIZE(x) (((x) & 0x1fff) << 16) | ||
353 | |||
354 | #define DC_WIN_PRESCALED_SIZE 0x706 | ||
355 | #define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0) | ||
356 | #define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) | ||
357 | |||
358 | #define DC_WIN_H_INITIAL_DDA 0x707 | ||
359 | #define DC_WIN_V_INITIAL_DDA 0x708 | ||
360 | #define DC_WIN_DDA_INC 0x709 | ||
361 | #define H_DDA_INC(x) (((x) & 0xffff) << 0) | ||
362 | #define V_DDA_INC(x) (((x) & 0xffff) << 16) | ||
363 | |||
364 | #define DC_WIN_LINE_STRIDE 0x70a | ||
365 | #define DC_WIN_BUF_STRIDE 0x70b | ||
366 | #define DC_WIN_UV_BUF_STRIDE 0x70c | ||
367 | #define DC_WIN_BUFFER_ADDR_MODE 0x70d | ||
368 | #define DC_WIN_DV_CONTROL 0x70e | ||
369 | |||
370 | #define DC_WIN_BLEND_NOKEY 0x70f | ||
371 | #define DC_WIN_BLEND_1WIN 0x710 | ||
372 | #define DC_WIN_BLEND_2WIN_X 0x711 | ||
373 | #define DC_WIN_BLEND_2WIN_Y 0x712 | ||
374 | #define DC_WIN_BLEND_3WIN_XY 0x713 | ||
375 | |||
376 | #define DC_WIN_HP_FETCH_CONTROL 0x714 | ||
377 | |||
378 | #define DC_WINBUF_START_ADDR 0x800 | ||
379 | #define DC_WINBUF_START_ADDR_NS 0x801 | ||
380 | #define DC_WINBUF_START_ADDR_U 0x802 | ||
381 | #define DC_WINBUF_START_ADDR_U_NS 0x803 | ||
382 | #define DC_WINBUF_START_ADDR_V 0x804 | ||
383 | #define DC_WINBUF_START_ADDR_V_NS 0x805 | ||
384 | |||
385 | #define DC_WINBUF_ADDR_H_OFFSET 0x806 | ||
386 | #define DC_WINBUF_ADDR_H_OFFSET_NS 0x807 | ||
387 | #define DC_WINBUF_ADDR_V_OFFSET 0x808 | ||
388 | #define DC_WINBUF_ADDR_V_OFFSET_NS 0x809 | ||
389 | |||
390 | #define DC_WINBUF_UFLOW_STATUS 0x80a | ||
391 | |||
392 | #define DC_WINBUF_AD_UFLOW_STATUS 0xbca | ||
393 | #define DC_WINBUF_BD_UFLOW_STATUS 0xdca | ||
394 | #define DC_WINBUF_CD_UFLOW_STATUS 0xfca | ||
395 | |||
396 | /* synchronization points */ | ||
397 | #define SYNCPT_VBLANK0 26 | ||
398 | #define SYNCPT_VBLANK1 27 | ||
399 | |||
400 | #endif /* TEGRA_DC_H */ | ||
diff --git a/drivers/gpu/host1x/drm/drm.c b/drivers/gpu/host1x/drm/drm.c deleted file mode 100644 index 8c61ceeaa12d..000000000000 --- a/drivers/gpu/host1x/drm/drm.c +++ /dev/null | |||
@@ -1,647 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Avionic Design GmbH | ||
3 | * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/of_address.h> | ||
12 | #include <linux/of_platform.h> | ||
13 | |||
14 | #include <linux/dma-mapping.h> | ||
15 | #include <asm/dma-iommu.h> | ||
16 | |||
17 | #include <drm/drm.h> | ||
18 | #include <drm/drmP.h> | ||
19 | |||
20 | #include "host1x_client.h" | ||
21 | #include "dev.h" | ||
22 | #include "drm.h" | ||
23 | #include "gem.h" | ||
24 | #include "syncpt.h" | ||
25 | |||
26 | #define DRIVER_NAME "tegra" | ||
27 | #define DRIVER_DESC "NVIDIA Tegra graphics" | ||
28 | #define DRIVER_DATE "20120330" | ||
29 | #define DRIVER_MAJOR 0 | ||
30 | #define DRIVER_MINOR 0 | ||
31 | #define DRIVER_PATCHLEVEL 0 | ||
32 | |||
33 | struct host1x_drm_client { | ||
34 | struct host1x_client *client; | ||
35 | struct device_node *np; | ||
36 | struct list_head list; | ||
37 | }; | ||
38 | |||
39 | static int host1x_add_drm_client(struct host1x_drm *host1x, | ||
40 | struct device_node *np) | ||
41 | { | ||
42 | struct host1x_drm_client *client; | ||
43 | |||
44 | client = kzalloc(sizeof(*client), GFP_KERNEL); | ||
45 | if (!client) | ||
46 | return -ENOMEM; | ||
47 | |||
48 | INIT_LIST_HEAD(&client->list); | ||
49 | client->np = of_node_get(np); | ||
50 | |||
51 | list_add_tail(&client->list, &host1x->drm_clients); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static int host1x_activate_drm_client(struct host1x_drm *host1x, | ||
57 | struct host1x_drm_client *drm, | ||
58 | struct host1x_client *client) | ||
59 | { | ||
60 | mutex_lock(&host1x->drm_clients_lock); | ||
61 | list_del_init(&drm->list); | ||
62 | list_add_tail(&drm->list, &host1x->drm_active); | ||
63 | drm->client = client; | ||
64 | mutex_unlock(&host1x->drm_clients_lock); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int host1x_remove_drm_client(struct host1x_drm *host1x, | ||
70 | struct host1x_drm_client *client) | ||
71 | { | ||
72 | mutex_lock(&host1x->drm_clients_lock); | ||
73 | list_del_init(&client->list); | ||
74 | mutex_unlock(&host1x->drm_clients_lock); | ||
75 | |||
76 | of_node_put(client->np); | ||
77 | kfree(client); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int host1x_parse_dt(struct host1x_drm *host1x) | ||
83 | { | ||
84 | static const char * const compat[] = { | ||
85 | "nvidia,tegra20-dc", | ||
86 | "nvidia,tegra20-hdmi", | ||
87 | "nvidia,tegra20-gr2d", | ||
88 | "nvidia,tegra30-dc", | ||
89 | "nvidia,tegra30-hdmi", | ||
90 | "nvidia,tegra30-gr2d", | ||
91 | }; | ||
92 | unsigned int i; | ||
93 | int err; | ||
94 | |||
95 | for (i = 0; i < ARRAY_SIZE(compat); i++) { | ||
96 | struct device_node *np; | ||
97 | |||
98 | for_each_child_of_node(host1x->dev->of_node, np) { | ||
99 | if (of_device_is_compatible(np, compat[i]) && | ||
100 | of_device_is_available(np)) { | ||
101 | err = host1x_add_drm_client(host1x, np); | ||
102 | if (err < 0) | ||
103 | return err; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | int host1x_drm_alloc(struct platform_device *pdev) | ||
112 | { | ||
113 | struct host1x_drm *host1x; | ||
114 | int err; | ||
115 | |||
116 | host1x = devm_kzalloc(&pdev->dev, sizeof(*host1x), GFP_KERNEL); | ||
117 | if (!host1x) | ||
118 | return -ENOMEM; | ||
119 | |||
120 | mutex_init(&host1x->drm_clients_lock); | ||
121 | INIT_LIST_HEAD(&host1x->drm_clients); | ||
122 | INIT_LIST_HEAD(&host1x->drm_active); | ||
123 | mutex_init(&host1x->clients_lock); | ||
124 | INIT_LIST_HEAD(&host1x->clients); | ||
125 | host1x->dev = &pdev->dev; | ||
126 | |||
127 | err = host1x_parse_dt(host1x); | ||
128 | if (err < 0) { | ||
129 | dev_err(&pdev->dev, "failed to parse DT: %d\n", err); | ||
130 | return err; | ||
131 | } | ||
132 | |||
133 | host1x_set_drm_data(&pdev->dev, host1x); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm) | ||
139 | { | ||
140 | struct host1x_client *client; | ||
141 | |||
142 | mutex_lock(&host1x->clients_lock); | ||
143 | |||
144 | list_for_each_entry(client, &host1x->clients, list) { | ||
145 | if (client->ops && client->ops->drm_init) { | ||
146 | int err = client->ops->drm_init(client, drm); | ||
147 | if (err < 0) { | ||
148 | dev_err(host1x->dev, | ||
149 | "DRM setup failed for %s: %d\n", | ||
150 | dev_name(client->dev), err); | ||
151 | mutex_unlock(&host1x->clients_lock); | ||
152 | return err; | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | |||
157 | mutex_unlock(&host1x->clients_lock); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | int host1x_drm_exit(struct host1x_drm *host1x) | ||
163 | { | ||
164 | struct platform_device *pdev = to_platform_device(host1x->dev); | ||
165 | struct host1x_client *client; | ||
166 | |||
167 | if (!host1x->drm) | ||
168 | return 0; | ||
169 | |||
170 | mutex_lock(&host1x->clients_lock); | ||
171 | |||
172 | list_for_each_entry_reverse(client, &host1x->clients, list) { | ||
173 | if (client->ops && client->ops->drm_exit) { | ||
174 | int err = client->ops->drm_exit(client); | ||
175 | if (err < 0) { | ||
176 | dev_err(host1x->dev, | ||
177 | "DRM cleanup failed for %s: %d\n", | ||
178 | dev_name(client->dev), err); | ||
179 | mutex_unlock(&host1x->clients_lock); | ||
180 | return err; | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | mutex_unlock(&host1x->clients_lock); | ||
186 | |||
187 | drm_platform_exit(&tegra_drm_driver, pdev); | ||
188 | host1x->drm = NULL; | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | int host1x_register_client(struct host1x_drm *host1x, | ||
194 | struct host1x_client *client) | ||
195 | { | ||
196 | struct host1x_drm_client *drm, *tmp; | ||
197 | int err; | ||
198 | |||
199 | mutex_lock(&host1x->clients_lock); | ||
200 | list_add_tail(&client->list, &host1x->clients); | ||
201 | mutex_unlock(&host1x->clients_lock); | ||
202 | |||
203 | list_for_each_entry_safe(drm, tmp, &host1x->drm_clients, list) | ||
204 | if (drm->np == client->dev->of_node) | ||
205 | host1x_activate_drm_client(host1x, drm, client); | ||
206 | |||
207 | if (list_empty(&host1x->drm_clients)) { | ||
208 | struct platform_device *pdev = to_platform_device(host1x->dev); | ||
209 | |||
210 | err = drm_platform_init(&tegra_drm_driver, pdev); | ||
211 | if (err < 0) { | ||
212 | dev_err(host1x->dev, "drm_platform_init(): %d\n", err); | ||
213 | return err; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | int host1x_unregister_client(struct host1x_drm *host1x, | ||
221 | struct host1x_client *client) | ||
222 | { | ||
223 | struct host1x_drm_client *drm, *tmp; | ||
224 | int err; | ||
225 | |||
226 | list_for_each_entry_safe(drm, tmp, &host1x->drm_active, list) { | ||
227 | if (drm->client == client) { | ||
228 | err = host1x_drm_exit(host1x); | ||
229 | if (err < 0) { | ||
230 | dev_err(host1x->dev, "host1x_drm_exit(): %d\n", | ||
231 | err); | ||
232 | return err; | ||
233 | } | ||
234 | |||
235 | host1x_remove_drm_client(host1x, drm); | ||
236 | break; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | mutex_lock(&host1x->clients_lock); | ||
241 | list_del_init(&client->list); | ||
242 | mutex_unlock(&host1x->clients_lock); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int tegra_drm_load(struct drm_device *drm, unsigned long flags) | ||
248 | { | ||
249 | struct host1x_drm *host1x; | ||
250 | int err; | ||
251 | |||
252 | host1x = host1x_get_drm_data(drm->dev); | ||
253 | drm->dev_private = host1x; | ||
254 | host1x->drm = drm; | ||
255 | |||
256 | drm_mode_config_init(drm); | ||
257 | |||
258 | err = host1x_drm_init(host1x, drm); | ||
259 | if (err < 0) | ||
260 | return err; | ||
261 | |||
262 | /* | ||
263 | * We don't use the drm_irq_install() helpers provided by the DRM | ||
264 | * core, so we need to set this manually in order to allow the | ||
265 | * DRM_IOCTL_WAIT_VBLANK to operate correctly. | ||
266 | */ | ||
267 | drm->irq_enabled = 1; | ||
268 | |||
269 | err = drm_vblank_init(drm, drm->mode_config.num_crtc); | ||
270 | if (err < 0) | ||
271 | return err; | ||
272 | |||
273 | err = tegra_drm_fb_init(drm); | ||
274 | if (err < 0) | ||
275 | return err; | ||
276 | |||
277 | drm_kms_helper_poll_init(drm); | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int tegra_drm_unload(struct drm_device *drm) | ||
283 | { | ||
284 | drm_kms_helper_poll_fini(drm); | ||
285 | tegra_drm_fb_exit(drm); | ||
286 | |||
287 | drm_mode_config_cleanup(drm); | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp) | ||
293 | { | ||
294 | struct host1x_drm_file *fpriv; | ||
295 | |||
296 | fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL); | ||
297 | if (!fpriv) | ||
298 | return -ENOMEM; | ||
299 | |||
300 | INIT_LIST_HEAD(&fpriv->contexts); | ||
301 | filp->driver_priv = fpriv; | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static void host1x_drm_context_free(struct host1x_drm_context *context) | ||
307 | { | ||
308 | context->client->ops->close_channel(context); | ||
309 | kfree(context); | ||
310 | } | ||
311 | |||
312 | static void tegra_drm_lastclose(struct drm_device *drm) | ||
313 | { | ||
314 | struct host1x_drm *host1x = drm->dev_private; | ||
315 | |||
316 | tegra_fbdev_restore_mode(host1x->fbdev); | ||
317 | } | ||
318 | |||
319 | #ifdef CONFIG_DRM_TEGRA_STAGING | ||
320 | static bool host1x_drm_file_owns_context(struct host1x_drm_file *file, | ||
321 | struct host1x_drm_context *context) | ||
322 | { | ||
323 | struct host1x_drm_context *ctx; | ||
324 | |||
325 | list_for_each_entry(ctx, &file->contexts, list) | ||
326 | if (ctx == context) | ||
327 | return true; | ||
328 | |||
329 | return false; | ||
330 | } | ||
331 | |||
332 | static int tegra_gem_create(struct drm_device *drm, void *data, | ||
333 | struct drm_file *file) | ||
334 | { | ||
335 | struct drm_tegra_gem_create *args = data; | ||
336 | struct tegra_bo *bo; | ||
337 | |||
338 | bo = tegra_bo_create_with_handle(file, drm, args->size, | ||
339 | &args->handle); | ||
340 | if (IS_ERR(bo)) | ||
341 | return PTR_ERR(bo); | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int tegra_gem_mmap(struct drm_device *drm, void *data, | ||
347 | struct drm_file *file) | ||
348 | { | ||
349 | struct drm_tegra_gem_mmap *args = data; | ||
350 | struct drm_gem_object *gem; | ||
351 | struct tegra_bo *bo; | ||
352 | |||
353 | gem = drm_gem_object_lookup(drm, file, args->handle); | ||
354 | if (!gem) | ||
355 | return -EINVAL; | ||
356 | |||
357 | bo = to_tegra_bo(gem); | ||
358 | |||
359 | args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node); | ||
360 | |||
361 | drm_gem_object_unreference(gem); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int tegra_syncpt_read(struct drm_device *drm, void *data, | ||
367 | struct drm_file *file) | ||
368 | { | ||
369 | struct drm_tegra_syncpt_read *args = data; | ||
370 | struct host1x *host = dev_get_drvdata(drm->dev); | ||
371 | struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id); | ||
372 | |||
373 | if (!sp) | ||
374 | return -EINVAL; | ||
375 | |||
376 | args->value = host1x_syncpt_read_min(sp); | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int tegra_syncpt_incr(struct drm_device *drm, void *data, | ||
381 | struct drm_file *file) | ||
382 | { | ||
383 | struct drm_tegra_syncpt_incr *args = data; | ||
384 | struct host1x *host = dev_get_drvdata(drm->dev); | ||
385 | struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id); | ||
386 | |||
387 | if (!sp) | ||
388 | return -EINVAL; | ||
389 | |||
390 | return host1x_syncpt_incr(sp); | ||
391 | } | ||
392 | |||
393 | static int tegra_syncpt_wait(struct drm_device *drm, void *data, | ||
394 | struct drm_file *file) | ||
395 | { | ||
396 | struct drm_tegra_syncpt_wait *args = data; | ||
397 | struct host1x *host = dev_get_drvdata(drm->dev); | ||
398 | struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id); | ||
399 | |||
400 | if (!sp) | ||
401 | return -EINVAL; | ||
402 | |||
403 | return host1x_syncpt_wait(sp, args->thresh, args->timeout, | ||
404 | &args->value); | ||
405 | } | ||
406 | |||
407 | static int tegra_open_channel(struct drm_device *drm, void *data, | ||
408 | struct drm_file *file) | ||
409 | { | ||
410 | struct drm_tegra_open_channel *args = data; | ||
411 | struct host1x_client *client; | ||
412 | struct host1x_drm_context *context; | ||
413 | struct host1x_drm_file *fpriv = file->driver_priv; | ||
414 | struct host1x_drm *host1x = drm->dev_private; | ||
415 | int err = -ENODEV; | ||
416 | |||
417 | context = kzalloc(sizeof(*context), GFP_KERNEL); | ||
418 | if (!context) | ||
419 | return -ENOMEM; | ||
420 | |||
421 | list_for_each_entry(client, &host1x->clients, list) | ||
422 | if (client->class == args->client) { | ||
423 | err = client->ops->open_channel(client, context); | ||
424 | if (err) | ||
425 | break; | ||
426 | |||
427 | context->client = client; | ||
428 | list_add(&context->list, &fpriv->contexts); | ||
429 | args->context = (uintptr_t)context; | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | kfree(context); | ||
434 | return err; | ||
435 | } | ||
436 | |||
437 | static int tegra_close_channel(struct drm_device *drm, void *data, | ||
438 | struct drm_file *file) | ||
439 | { | ||
440 | struct drm_tegra_close_channel *args = data; | ||
441 | struct host1x_drm_file *fpriv = file->driver_priv; | ||
442 | struct host1x_drm_context *context = | ||
443 | (struct host1x_drm_context *)(uintptr_t)args->context; | ||
444 | |||
445 | if (!host1x_drm_file_owns_context(fpriv, context)) | ||
446 | return -EINVAL; | ||
447 | |||
448 | list_del(&context->list); | ||
449 | host1x_drm_context_free(context); | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static int tegra_get_syncpt(struct drm_device *drm, void *data, | ||
455 | struct drm_file *file) | ||
456 | { | ||
457 | struct drm_tegra_get_syncpt *args = data; | ||
458 | struct host1x_drm_file *fpriv = file->driver_priv; | ||
459 | struct host1x_drm_context *context = | ||
460 | (struct host1x_drm_context *)(uintptr_t)args->context; | ||
461 | struct host1x_syncpt *syncpt; | ||
462 | |||
463 | if (!host1x_drm_file_owns_context(fpriv, context)) | ||
464 | return -ENODEV; | ||
465 | |||
466 | if (args->index >= context->client->num_syncpts) | ||
467 | return -EINVAL; | ||
468 | |||
469 | syncpt = context->client->syncpts[args->index]; | ||
470 | args->id = host1x_syncpt_id(syncpt); | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int tegra_submit(struct drm_device *drm, void *data, | ||
476 | struct drm_file *file) | ||
477 | { | ||
478 | struct drm_tegra_submit *args = data; | ||
479 | struct host1x_drm_file *fpriv = file->driver_priv; | ||
480 | struct host1x_drm_context *context = | ||
481 | (struct host1x_drm_context *)(uintptr_t)args->context; | ||
482 | |||
483 | if (!host1x_drm_file_owns_context(fpriv, context)) | ||
484 | return -ENODEV; | ||
485 | |||
486 | return context->client->ops->submit(context, args, drm, file); | ||
487 | } | ||
488 | #endif | ||
489 | |||
490 | static const struct drm_ioctl_desc tegra_drm_ioctls[] = { | ||
491 | #ifdef CONFIG_DRM_TEGRA_STAGING | ||
492 | DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED | DRM_AUTH), | ||
493 | DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, DRM_UNLOCKED), | ||
494 | DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, DRM_UNLOCKED), | ||
495 | DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, DRM_UNLOCKED), | ||
496 | DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, DRM_UNLOCKED), | ||
497 | DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, DRM_UNLOCKED), | ||
498 | DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, DRM_UNLOCKED), | ||
499 | DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, DRM_UNLOCKED), | ||
500 | DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, DRM_UNLOCKED), | ||
501 | #endif | ||
502 | }; | ||
503 | |||
504 | static const struct file_operations tegra_drm_fops = { | ||
505 | .owner = THIS_MODULE, | ||
506 | .open = drm_open, | ||
507 | .release = drm_release, | ||
508 | .unlocked_ioctl = drm_ioctl, | ||
509 | .mmap = tegra_drm_mmap, | ||
510 | .poll = drm_poll, | ||
511 | .read = drm_read, | ||
512 | #ifdef CONFIG_COMPAT | ||
513 | .compat_ioctl = drm_compat_ioctl, | ||
514 | #endif | ||
515 | .llseek = noop_llseek, | ||
516 | }; | ||
517 | |||
518 | static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe) | ||
519 | { | ||
520 | struct drm_crtc *crtc; | ||
521 | |||
522 | list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) { | ||
523 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
524 | |||
525 | if (dc->pipe == pipe) | ||
526 | return crtc; | ||
527 | } | ||
528 | |||
529 | return NULL; | ||
530 | } | ||
531 | |||
532 | static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc) | ||
533 | { | ||
534 | /* TODO: implement real hardware counter using syncpoints */ | ||
535 | return drm_vblank_count(dev, crtc); | ||
536 | } | ||
537 | |||
538 | static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) | ||
539 | { | ||
540 | struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); | ||
541 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
542 | |||
543 | if (!crtc) | ||
544 | return -ENODEV; | ||
545 | |||
546 | tegra_dc_enable_vblank(dc); | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe) | ||
552 | { | ||
553 | struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); | ||
554 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
555 | |||
556 | if (crtc) | ||
557 | tegra_dc_disable_vblank(dc); | ||
558 | } | ||
559 | |||
560 | static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file) | ||
561 | { | ||
562 | struct host1x_drm_file *fpriv = file->driver_priv; | ||
563 | struct host1x_drm_context *context, *tmp; | ||
564 | struct drm_crtc *crtc; | ||
565 | |||
566 | list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) | ||
567 | tegra_dc_cancel_page_flip(crtc, file); | ||
568 | |||
569 | list_for_each_entry_safe(context, tmp, &fpriv->contexts, list) | ||
570 | host1x_drm_context_free(context); | ||
571 | |||
572 | kfree(fpriv); | ||
573 | } | ||
574 | |||
575 | #ifdef CONFIG_DEBUG_FS | ||
576 | static int tegra_debugfs_framebuffers(struct seq_file *s, void *data) | ||
577 | { | ||
578 | struct drm_info_node *node = (struct drm_info_node *)s->private; | ||
579 | struct drm_device *drm = node->minor->dev; | ||
580 | struct drm_framebuffer *fb; | ||
581 | |||
582 | mutex_lock(&drm->mode_config.fb_lock); | ||
583 | |||
584 | list_for_each_entry(fb, &drm->mode_config.fb_list, head) { | ||
585 | seq_printf(s, "%3d: user size: %d x %d, depth %d, %d bpp, refcount %d\n", | ||
586 | fb->base.id, fb->width, fb->height, fb->depth, | ||
587 | fb->bits_per_pixel, | ||
588 | atomic_read(&fb->refcount.refcount)); | ||
589 | } | ||
590 | |||
591 | mutex_unlock(&drm->mode_config.fb_lock); | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static struct drm_info_list tegra_debugfs_list[] = { | ||
597 | { "framebuffers", tegra_debugfs_framebuffers, 0 }, | ||
598 | }; | ||
599 | |||
600 | static int tegra_debugfs_init(struct drm_minor *minor) | ||
601 | { | ||
602 | return drm_debugfs_create_files(tegra_debugfs_list, | ||
603 | ARRAY_SIZE(tegra_debugfs_list), | ||
604 | minor->debugfs_root, minor); | ||
605 | } | ||
606 | |||
607 | static void tegra_debugfs_cleanup(struct drm_minor *minor) | ||
608 | { | ||
609 | drm_debugfs_remove_files(tegra_debugfs_list, | ||
610 | ARRAY_SIZE(tegra_debugfs_list), minor); | ||
611 | } | ||
612 | #endif | ||
613 | |||
614 | struct drm_driver tegra_drm_driver = { | ||
615 | .driver_features = DRIVER_MODESET | DRIVER_GEM, | ||
616 | .load = tegra_drm_load, | ||
617 | .unload = tegra_drm_unload, | ||
618 | .open = tegra_drm_open, | ||
619 | .preclose = tegra_drm_preclose, | ||
620 | .lastclose = tegra_drm_lastclose, | ||
621 | |||
622 | .get_vblank_counter = tegra_drm_get_vblank_counter, | ||
623 | .enable_vblank = tegra_drm_enable_vblank, | ||
624 | .disable_vblank = tegra_drm_disable_vblank, | ||
625 | |||
626 | #if defined(CONFIG_DEBUG_FS) | ||
627 | .debugfs_init = tegra_debugfs_init, | ||
628 | .debugfs_cleanup = tegra_debugfs_cleanup, | ||
629 | #endif | ||
630 | |||
631 | .gem_free_object = tegra_bo_free_object, | ||
632 | .gem_vm_ops = &tegra_bo_vm_ops, | ||
633 | .dumb_create = tegra_bo_dumb_create, | ||
634 | .dumb_map_offset = tegra_bo_dumb_map_offset, | ||
635 | .dumb_destroy = drm_gem_dumb_destroy, | ||
636 | |||
637 | .ioctls = tegra_drm_ioctls, | ||
638 | .num_ioctls = ARRAY_SIZE(tegra_drm_ioctls), | ||
639 | .fops = &tegra_drm_fops, | ||
640 | |||
641 | .name = DRIVER_NAME, | ||
642 | .desc = DRIVER_DESC, | ||
643 | .date = DRIVER_DATE, | ||
644 | .major = DRIVER_MAJOR, | ||
645 | .minor = DRIVER_MINOR, | ||
646 | .patchlevel = DRIVER_PATCHLEVEL, | ||
647 | }; | ||
diff --git a/drivers/gpu/host1x/drm/drm.h b/drivers/gpu/host1x/drm/drm.h deleted file mode 100644 index 02ce020f2575..000000000000 --- a/drivers/gpu/host1x/drm/drm.h +++ /dev/null | |||
@@ -1,271 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Avionic Design GmbH | ||
3 | * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #ifndef HOST1X_DRM_H | ||
11 | #define HOST1X_DRM_H 1 | ||
12 | |||
13 | #include <drm/drmP.h> | ||
14 | #include <drm/drm_crtc_helper.h> | ||
15 | #include <drm/drm_edid.h> | ||
16 | #include <drm/drm_fb_helper.h> | ||
17 | #include <drm/drm_fixed.h> | ||
18 | #include <uapi/drm/tegra_drm.h> | ||
19 | |||
20 | #include "host1x.h" | ||
21 | |||
22 | struct tegra_fb { | ||
23 | struct drm_framebuffer base; | ||
24 | struct tegra_bo **planes; | ||
25 | unsigned int num_planes; | ||
26 | }; | ||
27 | |||
28 | struct tegra_fbdev { | ||
29 | struct drm_fb_helper base; | ||
30 | struct tegra_fb *fb; | ||
31 | }; | ||
32 | |||
33 | struct host1x_drm { | ||
34 | struct drm_device *drm; | ||
35 | struct device *dev; | ||
36 | void __iomem *regs; | ||
37 | struct clk *clk; | ||
38 | int syncpt; | ||
39 | int irq; | ||
40 | |||
41 | struct mutex drm_clients_lock; | ||
42 | struct list_head drm_clients; | ||
43 | struct list_head drm_active; | ||
44 | |||
45 | struct mutex clients_lock; | ||
46 | struct list_head clients; | ||
47 | |||
48 | struct tegra_fbdev *fbdev; | ||
49 | }; | ||
50 | |||
51 | struct host1x_client; | ||
52 | |||
53 | struct host1x_drm_context { | ||
54 | struct host1x_client *client; | ||
55 | struct host1x_channel *channel; | ||
56 | struct list_head list; | ||
57 | }; | ||
58 | |||
59 | struct host1x_client_ops { | ||
60 | int (*drm_init)(struct host1x_client *client, struct drm_device *drm); | ||
61 | int (*drm_exit)(struct host1x_client *client); | ||
62 | int (*open_channel)(struct host1x_client *client, | ||
63 | struct host1x_drm_context *context); | ||
64 | void (*close_channel)(struct host1x_drm_context *context); | ||
65 | int (*submit)(struct host1x_drm_context *context, | ||
66 | struct drm_tegra_submit *args, struct drm_device *drm, | ||
67 | struct drm_file *file); | ||
68 | }; | ||
69 | |||
70 | struct host1x_drm_file { | ||
71 | struct list_head contexts; | ||
72 | }; | ||
73 | |||
74 | struct host1x_client { | ||
75 | struct host1x_drm *host1x; | ||
76 | struct device *dev; | ||
77 | |||
78 | const struct host1x_client_ops *ops; | ||
79 | |||
80 | enum host1x_class class; | ||
81 | struct host1x_channel *channel; | ||
82 | |||
83 | struct host1x_syncpt **syncpts; | ||
84 | unsigned int num_syncpts; | ||
85 | |||
86 | struct list_head list; | ||
87 | }; | ||
88 | |||
89 | extern int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm); | ||
90 | extern int host1x_drm_exit(struct host1x_drm *host1x); | ||
91 | |||
92 | extern int host1x_register_client(struct host1x_drm *host1x, | ||
93 | struct host1x_client *client); | ||
94 | extern int host1x_unregister_client(struct host1x_drm *host1x, | ||
95 | struct host1x_client *client); | ||
96 | |||
97 | struct tegra_output; | ||
98 | |||
99 | struct tegra_dc { | ||
100 | struct host1x_client client; | ||
101 | spinlock_t lock; | ||
102 | |||
103 | struct host1x_drm *host1x; | ||
104 | struct device *dev; | ||
105 | |||
106 | struct drm_crtc base; | ||
107 | int pipe; | ||
108 | |||
109 | struct clk *clk; | ||
110 | |||
111 | void __iomem *regs; | ||
112 | int irq; | ||
113 | |||
114 | struct tegra_output *rgb; | ||
115 | |||
116 | struct list_head list; | ||
117 | |||
118 | struct drm_info_list *debugfs_files; | ||
119 | struct drm_minor *minor; | ||
120 | struct dentry *debugfs; | ||
121 | |||
122 | /* page-flip handling */ | ||
123 | struct drm_pending_vblank_event *event; | ||
124 | }; | ||
125 | |||
126 | static inline struct tegra_dc *host1x_client_to_dc(struct host1x_client *client) | ||
127 | { | ||
128 | return container_of(client, struct tegra_dc, client); | ||
129 | } | ||
130 | |||
131 | static inline struct tegra_dc *to_tegra_dc(struct drm_crtc *crtc) | ||
132 | { | ||
133 | return container_of(crtc, struct tegra_dc, base); | ||
134 | } | ||
135 | |||
136 | static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long value, | ||
137 | unsigned long reg) | ||
138 | { | ||
139 | writel(value, dc->regs + (reg << 2)); | ||
140 | } | ||
141 | |||
142 | static inline unsigned long tegra_dc_readl(struct tegra_dc *dc, | ||
143 | unsigned long reg) | ||
144 | { | ||
145 | return readl(dc->regs + (reg << 2)); | ||
146 | } | ||
147 | |||
148 | struct tegra_dc_window { | ||
149 | struct { | ||
150 | unsigned int x; | ||
151 | unsigned int y; | ||
152 | unsigned int w; | ||
153 | unsigned int h; | ||
154 | } src; | ||
155 | struct { | ||
156 | unsigned int x; | ||
157 | unsigned int y; | ||
158 | unsigned int w; | ||
159 | unsigned int h; | ||
160 | } dst; | ||
161 | unsigned int bits_per_pixel; | ||
162 | unsigned int format; | ||
163 | unsigned int stride[2]; | ||
164 | unsigned long base[3]; | ||
165 | }; | ||
166 | |||
167 | /* from dc.c */ | ||
168 | extern unsigned int tegra_dc_format(uint32_t format); | ||
169 | extern int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | ||
170 | const struct tegra_dc_window *window); | ||
171 | extern void tegra_dc_enable_vblank(struct tegra_dc *dc); | ||
172 | extern void tegra_dc_disable_vblank(struct tegra_dc *dc); | ||
173 | extern void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, | ||
174 | struct drm_file *file); | ||
175 | |||
176 | struct tegra_output_ops { | ||
177 | int (*enable)(struct tegra_output *output); | ||
178 | int (*disable)(struct tegra_output *output); | ||
179 | int (*setup_clock)(struct tegra_output *output, struct clk *clk, | ||
180 | unsigned long pclk); | ||
181 | int (*check_mode)(struct tegra_output *output, | ||
182 | struct drm_display_mode *mode, | ||
183 | enum drm_mode_status *status); | ||
184 | }; | ||
185 | |||
186 | enum tegra_output_type { | ||
187 | TEGRA_OUTPUT_RGB, | ||
188 | TEGRA_OUTPUT_HDMI, | ||
189 | }; | ||
190 | |||
191 | struct tegra_output { | ||
192 | struct device_node *of_node; | ||
193 | struct device *dev; | ||
194 | |||
195 | const struct tegra_output_ops *ops; | ||
196 | enum tegra_output_type type; | ||
197 | |||
198 | struct i2c_adapter *ddc; | ||
199 | const struct edid *edid; | ||
200 | unsigned int hpd_irq; | ||
201 | int hpd_gpio; | ||
202 | |||
203 | struct drm_encoder encoder; | ||
204 | struct drm_connector connector; | ||
205 | }; | ||
206 | |||
207 | static inline struct tegra_output *encoder_to_output(struct drm_encoder *e) | ||
208 | { | ||
209 | return container_of(e, struct tegra_output, encoder); | ||
210 | } | ||
211 | |||
212 | static inline struct tegra_output *connector_to_output(struct drm_connector *c) | ||
213 | { | ||
214 | return container_of(c, struct tegra_output, connector); | ||
215 | } | ||
216 | |||
217 | static inline int tegra_output_enable(struct tegra_output *output) | ||
218 | { | ||
219 | if (output && output->ops && output->ops->enable) | ||
220 | return output->ops->enable(output); | ||
221 | |||
222 | return output ? -ENOSYS : -EINVAL; | ||
223 | } | ||
224 | |||
225 | static inline int tegra_output_disable(struct tegra_output *output) | ||
226 | { | ||
227 | if (output && output->ops && output->ops->disable) | ||
228 | return output->ops->disable(output); | ||
229 | |||
230 | return output ? -ENOSYS : -EINVAL; | ||
231 | } | ||
232 | |||
233 | static inline int tegra_output_setup_clock(struct tegra_output *output, | ||
234 | struct clk *clk, unsigned long pclk) | ||
235 | { | ||
236 | if (output && output->ops && output->ops->setup_clock) | ||
237 | return output->ops->setup_clock(output, clk, pclk); | ||
238 | |||
239 | return output ? -ENOSYS : -EINVAL; | ||
240 | } | ||
241 | |||
242 | static inline int tegra_output_check_mode(struct tegra_output *output, | ||
243 | struct drm_display_mode *mode, | ||
244 | enum drm_mode_status *status) | ||
245 | { | ||
246 | if (output && output->ops && output->ops->check_mode) | ||
247 | return output->ops->check_mode(output, mode, status); | ||
248 | |||
249 | return output ? -ENOSYS : -EINVAL; | ||
250 | } | ||
251 | |||
252 | /* from rgb.c */ | ||
253 | extern int tegra_dc_rgb_probe(struct tegra_dc *dc); | ||
254 | extern int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc); | ||
255 | extern int tegra_dc_rgb_exit(struct tegra_dc *dc); | ||
256 | |||
257 | /* from output.c */ | ||
258 | extern int tegra_output_parse_dt(struct tegra_output *output); | ||
259 | extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output); | ||
260 | extern int tegra_output_exit(struct tegra_output *output); | ||
261 | |||
262 | /* from fb.c */ | ||
263 | struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, | ||
264 | unsigned int index); | ||
265 | extern int tegra_drm_fb_init(struct drm_device *drm); | ||
266 | extern void tegra_drm_fb_exit(struct drm_device *drm); | ||
267 | extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); | ||
268 | |||
269 | extern struct drm_driver tegra_drm_driver; | ||
270 | |||
271 | #endif /* HOST1X_DRM_H */ | ||
diff --git a/drivers/gpu/host1x/drm/fb.c b/drivers/gpu/host1x/drm/fb.c deleted file mode 100644 index 979a3e32b78b..000000000000 --- a/drivers/gpu/host1x/drm/fb.c +++ /dev/null | |||
@@ -1,374 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012-2013 Avionic Design GmbH | ||
3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | ||
5 | * Based on the KMS/FB CMA helpers | ||
6 | * Copyright (C) 2012 Analog Device Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | |||
15 | #include "drm.h" | ||
16 | #include "gem.h" | ||
17 | |||
18 | static inline struct tegra_fb *to_tegra_fb(struct drm_framebuffer *fb) | ||
19 | { | ||
20 | return container_of(fb, struct tegra_fb, base); | ||
21 | } | ||
22 | |||
23 | static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper) | ||
24 | { | ||
25 | return container_of(helper, struct tegra_fbdev, base); | ||
26 | } | ||
27 | |||
28 | struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, | ||
29 | unsigned int index) | ||
30 | { | ||
31 | struct tegra_fb *fb = to_tegra_fb(framebuffer); | ||
32 | |||
33 | if (index >= drm_format_num_planes(framebuffer->pixel_format)) | ||
34 | return NULL; | ||
35 | |||
36 | return fb->planes[index]; | ||
37 | } | ||
38 | |||
39 | static void tegra_fb_destroy(struct drm_framebuffer *framebuffer) | ||
40 | { | ||
41 | struct tegra_fb *fb = to_tegra_fb(framebuffer); | ||
42 | unsigned int i; | ||
43 | |||
44 | for (i = 0; i < fb->num_planes; i++) { | ||
45 | struct tegra_bo *bo = fb->planes[i]; | ||
46 | |||
47 | if (bo) | ||
48 | drm_gem_object_unreference_unlocked(&bo->gem); | ||
49 | } | ||
50 | |||
51 | drm_framebuffer_cleanup(framebuffer); | ||
52 | kfree(fb->planes); | ||
53 | kfree(fb); | ||
54 | } | ||
55 | |||
56 | static int tegra_fb_create_handle(struct drm_framebuffer *framebuffer, | ||
57 | struct drm_file *file, unsigned int *handle) | ||
58 | { | ||
59 | struct tegra_fb *fb = to_tegra_fb(framebuffer); | ||
60 | |||
61 | return drm_gem_handle_create(file, &fb->planes[0]->gem, handle); | ||
62 | } | ||
63 | |||
64 | static struct drm_framebuffer_funcs tegra_fb_funcs = { | ||
65 | .destroy = tegra_fb_destroy, | ||
66 | .create_handle = tegra_fb_create_handle, | ||
67 | }; | ||
68 | |||
69 | static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm, | ||
70 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
71 | struct tegra_bo **planes, | ||
72 | unsigned int num_planes) | ||
73 | { | ||
74 | struct tegra_fb *fb; | ||
75 | unsigned int i; | ||
76 | int err; | ||
77 | |||
78 | fb = kzalloc(sizeof(*fb), GFP_KERNEL); | ||
79 | if (!fb) | ||
80 | return ERR_PTR(-ENOMEM); | ||
81 | |||
82 | fb->planes = kzalloc(num_planes * sizeof(*planes), GFP_KERNEL); | ||
83 | if (!fb->planes) | ||
84 | return ERR_PTR(-ENOMEM); | ||
85 | |||
86 | fb->num_planes = num_planes; | ||
87 | |||
88 | drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); | ||
89 | |||
90 | for (i = 0; i < fb->num_planes; i++) | ||
91 | fb->planes[i] = planes[i]; | ||
92 | |||
93 | err = drm_framebuffer_init(drm, &fb->base, &tegra_fb_funcs); | ||
94 | if (err < 0) { | ||
95 | dev_err(drm->dev, "failed to initialize framebuffer: %d\n", | ||
96 | err); | ||
97 | kfree(fb->planes); | ||
98 | kfree(fb); | ||
99 | return ERR_PTR(err); | ||
100 | } | ||
101 | |||
102 | return fb; | ||
103 | } | ||
104 | |||
105 | static struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, | ||
106 | struct drm_file *file, | ||
107 | struct drm_mode_fb_cmd2 *cmd) | ||
108 | { | ||
109 | unsigned int hsub, vsub, i; | ||
110 | struct tegra_bo *planes[4]; | ||
111 | struct drm_gem_object *gem; | ||
112 | struct tegra_fb *fb; | ||
113 | int err; | ||
114 | |||
115 | hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format); | ||
116 | vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format); | ||
117 | |||
118 | for (i = 0; i < drm_format_num_planes(cmd->pixel_format); i++) { | ||
119 | unsigned int width = cmd->width / (i ? hsub : 1); | ||
120 | unsigned int height = cmd->height / (i ? vsub : 1); | ||
121 | unsigned int size, bpp; | ||
122 | |||
123 | gem = drm_gem_object_lookup(drm, file, cmd->handles[i]); | ||
124 | if (!gem) { | ||
125 | err = -ENXIO; | ||
126 | goto unreference; | ||
127 | } | ||
128 | |||
129 | bpp = drm_format_plane_cpp(cmd->pixel_format, i); | ||
130 | |||
131 | size = (height - 1) * cmd->pitches[i] + | ||
132 | width * bpp + cmd->offsets[i]; | ||
133 | |||
134 | if (gem->size < size) { | ||
135 | err = -EINVAL; | ||
136 | goto unreference; | ||
137 | } | ||
138 | |||
139 | planes[i] = to_tegra_bo(gem); | ||
140 | } | ||
141 | |||
142 | fb = tegra_fb_alloc(drm, cmd, planes, i); | ||
143 | if (IS_ERR(fb)) { | ||
144 | err = PTR_ERR(fb); | ||
145 | goto unreference; | ||
146 | } | ||
147 | |||
148 | return &fb->base; | ||
149 | |||
150 | unreference: | ||
151 | while (i--) | ||
152 | drm_gem_object_unreference_unlocked(&planes[i]->gem); | ||
153 | |||
154 | return ERR_PTR(err); | ||
155 | } | ||
156 | |||
157 | static struct fb_ops tegra_fb_ops = { | ||
158 | .owner = THIS_MODULE, | ||
159 | .fb_fillrect = sys_fillrect, | ||
160 | .fb_copyarea = sys_copyarea, | ||
161 | .fb_imageblit = sys_imageblit, | ||
162 | .fb_check_var = drm_fb_helper_check_var, | ||
163 | .fb_set_par = drm_fb_helper_set_par, | ||
164 | .fb_blank = drm_fb_helper_blank, | ||
165 | .fb_pan_display = drm_fb_helper_pan_display, | ||
166 | .fb_setcmap = drm_fb_helper_setcmap, | ||
167 | }; | ||
168 | |||
169 | static int tegra_fbdev_probe(struct drm_fb_helper *helper, | ||
170 | struct drm_fb_helper_surface_size *sizes) | ||
171 | { | ||
172 | struct tegra_fbdev *fbdev = to_tegra_fbdev(helper); | ||
173 | struct drm_device *drm = helper->dev; | ||
174 | struct drm_mode_fb_cmd2 cmd = { 0 }; | ||
175 | unsigned int bytes_per_pixel; | ||
176 | struct drm_framebuffer *fb; | ||
177 | unsigned long offset; | ||
178 | struct fb_info *info; | ||
179 | struct tegra_bo *bo; | ||
180 | size_t size; | ||
181 | int err; | ||
182 | |||
183 | bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); | ||
184 | |||
185 | cmd.width = sizes->surface_width; | ||
186 | cmd.height = sizes->surface_height; | ||
187 | cmd.pitches[0] = sizes->surface_width * bytes_per_pixel; | ||
188 | cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, | ||
189 | sizes->surface_depth); | ||
190 | |||
191 | size = cmd.pitches[0] * cmd.height; | ||
192 | |||
193 | bo = tegra_bo_create(drm, size); | ||
194 | if (IS_ERR(bo)) | ||
195 | return PTR_ERR(bo); | ||
196 | |||
197 | info = framebuffer_alloc(0, drm->dev); | ||
198 | if (!info) { | ||
199 | dev_err(drm->dev, "failed to allocate framebuffer info\n"); | ||
200 | tegra_bo_free_object(&bo->gem); | ||
201 | return -ENOMEM; | ||
202 | } | ||
203 | |||
204 | fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1); | ||
205 | if (IS_ERR(fbdev->fb)) { | ||
206 | dev_err(drm->dev, "failed to allocate DRM framebuffer\n"); | ||
207 | err = PTR_ERR(fbdev->fb); | ||
208 | goto release; | ||
209 | } | ||
210 | |||
211 | fb = &fbdev->fb->base; | ||
212 | helper->fb = fb; | ||
213 | helper->fbdev = info; | ||
214 | |||
215 | info->par = helper; | ||
216 | info->flags = FBINFO_FLAG_DEFAULT; | ||
217 | info->fbops = &tegra_fb_ops; | ||
218 | |||
219 | err = fb_alloc_cmap(&info->cmap, 256, 0); | ||
220 | if (err < 0) { | ||
221 | dev_err(drm->dev, "failed to allocate color map: %d\n", err); | ||
222 | goto destroy; | ||
223 | } | ||
224 | |||
225 | drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); | ||
226 | drm_fb_helper_fill_var(info, helper, fb->width, fb->height); | ||
227 | |||
228 | offset = info->var.xoffset * bytes_per_pixel + | ||
229 | info->var.yoffset * fb->pitches[0]; | ||
230 | |||
231 | drm->mode_config.fb_base = (resource_size_t)bo->paddr; | ||
232 | info->screen_base = bo->vaddr + offset; | ||
233 | info->screen_size = size; | ||
234 | info->fix.smem_start = (unsigned long)(bo->paddr + offset); | ||
235 | info->fix.smem_len = size; | ||
236 | |||
237 | return 0; | ||
238 | |||
239 | destroy: | ||
240 | drm_framebuffer_unregister_private(fb); | ||
241 | tegra_fb_destroy(fb); | ||
242 | release: | ||
243 | framebuffer_release(info); | ||
244 | return err; | ||
245 | } | ||
246 | |||
247 | static struct drm_fb_helper_funcs tegra_fb_helper_funcs = { | ||
248 | .fb_probe = tegra_fbdev_probe, | ||
249 | }; | ||
250 | |||
251 | static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm, | ||
252 | unsigned int preferred_bpp, | ||
253 | unsigned int num_crtc, | ||
254 | unsigned int max_connectors) | ||
255 | { | ||
256 | struct drm_fb_helper *helper; | ||
257 | struct tegra_fbdev *fbdev; | ||
258 | int err; | ||
259 | |||
260 | fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); | ||
261 | if (!fbdev) { | ||
262 | dev_err(drm->dev, "failed to allocate DRM fbdev\n"); | ||
263 | return ERR_PTR(-ENOMEM); | ||
264 | } | ||
265 | |||
266 | fbdev->base.funcs = &tegra_fb_helper_funcs; | ||
267 | helper = &fbdev->base; | ||
268 | |||
269 | err = drm_fb_helper_init(drm, &fbdev->base, num_crtc, max_connectors); | ||
270 | if (err < 0) { | ||
271 | dev_err(drm->dev, "failed to initialize DRM FB helper\n"); | ||
272 | goto free; | ||
273 | } | ||
274 | |||
275 | err = drm_fb_helper_single_add_all_connectors(&fbdev->base); | ||
276 | if (err < 0) { | ||
277 | dev_err(drm->dev, "failed to add connectors\n"); | ||
278 | goto fini; | ||
279 | } | ||
280 | |||
281 | drm_helper_disable_unused_functions(drm); | ||
282 | |||
283 | err = drm_fb_helper_initial_config(&fbdev->base, preferred_bpp); | ||
284 | if (err < 0) { | ||
285 | dev_err(drm->dev, "failed to set initial configuration\n"); | ||
286 | goto fini; | ||
287 | } | ||
288 | |||
289 | return fbdev; | ||
290 | |||
291 | fini: | ||
292 | drm_fb_helper_fini(&fbdev->base); | ||
293 | free: | ||
294 | kfree(fbdev); | ||
295 | return ERR_PTR(err); | ||
296 | } | ||
297 | |||
298 | static void tegra_fbdev_free(struct tegra_fbdev *fbdev) | ||
299 | { | ||
300 | struct fb_info *info = fbdev->base.fbdev; | ||
301 | |||
302 | if (info) { | ||
303 | int err; | ||
304 | |||
305 | err = unregister_framebuffer(info); | ||
306 | if (err < 0) | ||
307 | DRM_DEBUG_KMS("failed to unregister framebuffer\n"); | ||
308 | |||
309 | if (info->cmap.len) | ||
310 | fb_dealloc_cmap(&info->cmap); | ||
311 | |||
312 | framebuffer_release(info); | ||
313 | } | ||
314 | |||
315 | if (fbdev->fb) { | ||
316 | drm_framebuffer_unregister_private(&fbdev->fb->base); | ||
317 | tegra_fb_destroy(&fbdev->fb->base); | ||
318 | } | ||
319 | |||
320 | drm_fb_helper_fini(&fbdev->base); | ||
321 | kfree(fbdev); | ||
322 | } | ||
323 | |||
324 | static void tegra_fb_output_poll_changed(struct drm_device *drm) | ||
325 | { | ||
326 | struct host1x_drm *host1x = drm->dev_private; | ||
327 | |||
328 | if (host1x->fbdev) | ||
329 | drm_fb_helper_hotplug_event(&host1x->fbdev->base); | ||
330 | } | ||
331 | |||
332 | static const struct drm_mode_config_funcs tegra_drm_mode_funcs = { | ||
333 | .fb_create = tegra_fb_create, | ||
334 | .output_poll_changed = tegra_fb_output_poll_changed, | ||
335 | }; | ||
336 | |||
337 | int tegra_drm_fb_init(struct drm_device *drm) | ||
338 | { | ||
339 | struct host1x_drm *host1x = drm->dev_private; | ||
340 | struct tegra_fbdev *fbdev; | ||
341 | |||
342 | drm->mode_config.min_width = 0; | ||
343 | drm->mode_config.min_height = 0; | ||
344 | |||
345 | drm->mode_config.max_width = 4096; | ||
346 | drm->mode_config.max_height = 4096; | ||
347 | |||
348 | drm->mode_config.funcs = &tegra_drm_mode_funcs; | ||
349 | |||
350 | fbdev = tegra_fbdev_create(drm, 32, drm->mode_config.num_crtc, | ||
351 | drm->mode_config.num_connector); | ||
352 | if (IS_ERR(fbdev)) | ||
353 | return PTR_ERR(fbdev); | ||
354 | |||
355 | host1x->fbdev = fbdev; | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | void tegra_drm_fb_exit(struct drm_device *drm) | ||
361 | { | ||
362 | struct host1x_drm *host1x = drm->dev_private; | ||
363 | |||
364 | tegra_fbdev_free(host1x->fbdev); | ||
365 | } | ||
366 | |||
367 | void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev) | ||
368 | { | ||
369 | if (fbdev) { | ||
370 | drm_modeset_lock_all(fbdev->base.dev); | ||
371 | drm_fb_helper_restore_fbdev_mode(&fbdev->base); | ||
372 | drm_modeset_unlock_all(fbdev->base.dev); | ||
373 | } | ||
374 | } | ||
diff --git a/drivers/gpu/host1x/drm/gem.c b/drivers/gpu/host1x/drm/gem.c deleted file mode 100644 index 59623de4ee15..000000000000 --- a/drivers/gpu/host1x/drm/gem.c +++ /dev/null | |||
@@ -1,258 +0,0 @@ | |||
1 | /* | ||
2 | * NVIDIA Tegra DRM GEM helper functions | ||
3 | * | ||
4 | * Copyright (C) 2012 Sascha Hauer, Pengutronix | ||
5 | * Copyright (C) 2013 NVIDIA CORPORATION, All rights reserved. | ||
6 | * | ||
7 | * Based on the GEM/CMA helpers | ||
8 | * | ||
9 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #include <linux/mm.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/export.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | |||
27 | #include <drm/drmP.h> | ||
28 | #include <drm/drm.h> | ||
29 | |||
30 | #include "gem.h" | ||
31 | |||
32 | static inline struct tegra_bo *host1x_to_drm_bo(struct host1x_bo *bo) | ||
33 | { | ||
34 | return container_of(bo, struct tegra_bo, base); | ||
35 | } | ||
36 | |||
37 | static void tegra_bo_put(struct host1x_bo *bo) | ||
38 | { | ||
39 | struct tegra_bo *obj = host1x_to_drm_bo(bo); | ||
40 | struct drm_device *drm = obj->gem.dev; | ||
41 | |||
42 | mutex_lock(&drm->struct_mutex); | ||
43 | drm_gem_object_unreference(&obj->gem); | ||
44 | mutex_unlock(&drm->struct_mutex); | ||
45 | } | ||
46 | |||
47 | static dma_addr_t tegra_bo_pin(struct host1x_bo *bo, struct sg_table **sgt) | ||
48 | { | ||
49 | struct tegra_bo *obj = host1x_to_drm_bo(bo); | ||
50 | |||
51 | return obj->paddr; | ||
52 | } | ||
53 | |||
54 | static void tegra_bo_unpin(struct host1x_bo *bo, struct sg_table *sgt) | ||
55 | { | ||
56 | } | ||
57 | |||
58 | static void *tegra_bo_mmap(struct host1x_bo *bo) | ||
59 | { | ||
60 | struct tegra_bo *obj = host1x_to_drm_bo(bo); | ||
61 | |||
62 | return obj->vaddr; | ||
63 | } | ||
64 | |||
65 | static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) | ||
66 | { | ||
67 | } | ||
68 | |||
69 | static void *tegra_bo_kmap(struct host1x_bo *bo, unsigned int page) | ||
70 | { | ||
71 | struct tegra_bo *obj = host1x_to_drm_bo(bo); | ||
72 | |||
73 | return obj->vaddr + page * PAGE_SIZE; | ||
74 | } | ||
75 | |||
76 | static void tegra_bo_kunmap(struct host1x_bo *bo, unsigned int page, | ||
77 | void *addr) | ||
78 | { | ||
79 | } | ||
80 | |||
81 | static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo) | ||
82 | { | ||
83 | struct tegra_bo *obj = host1x_to_drm_bo(bo); | ||
84 | struct drm_device *drm = obj->gem.dev; | ||
85 | |||
86 | mutex_lock(&drm->struct_mutex); | ||
87 | drm_gem_object_reference(&obj->gem); | ||
88 | mutex_unlock(&drm->struct_mutex); | ||
89 | |||
90 | return bo; | ||
91 | } | ||
92 | |||
93 | const struct host1x_bo_ops tegra_bo_ops = { | ||
94 | .get = tegra_bo_get, | ||
95 | .put = tegra_bo_put, | ||
96 | .pin = tegra_bo_pin, | ||
97 | .unpin = tegra_bo_unpin, | ||
98 | .mmap = tegra_bo_mmap, | ||
99 | .munmap = tegra_bo_munmap, | ||
100 | .kmap = tegra_bo_kmap, | ||
101 | .kunmap = tegra_bo_kunmap, | ||
102 | }; | ||
103 | |||
104 | static void tegra_bo_destroy(struct drm_device *drm, struct tegra_bo *bo) | ||
105 | { | ||
106 | dma_free_writecombine(drm->dev, bo->gem.size, bo->vaddr, bo->paddr); | ||
107 | } | ||
108 | |||
109 | struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size) | ||
110 | { | ||
111 | struct tegra_bo *bo; | ||
112 | int err; | ||
113 | |||
114 | bo = kzalloc(sizeof(*bo), GFP_KERNEL); | ||
115 | if (!bo) | ||
116 | return ERR_PTR(-ENOMEM); | ||
117 | |||
118 | host1x_bo_init(&bo->base, &tegra_bo_ops); | ||
119 | size = round_up(size, PAGE_SIZE); | ||
120 | |||
121 | bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr, | ||
122 | GFP_KERNEL | __GFP_NOWARN); | ||
123 | if (!bo->vaddr) { | ||
124 | dev_err(drm->dev, "failed to allocate buffer with size %u\n", | ||
125 | size); | ||
126 | err = -ENOMEM; | ||
127 | goto err_dma; | ||
128 | } | ||
129 | |||
130 | err = drm_gem_object_init(drm, &bo->gem, size); | ||
131 | if (err) | ||
132 | goto err_init; | ||
133 | |||
134 | err = drm_gem_create_mmap_offset(&bo->gem); | ||
135 | if (err) | ||
136 | goto err_mmap; | ||
137 | |||
138 | return bo; | ||
139 | |||
140 | err_mmap: | ||
141 | drm_gem_object_release(&bo->gem); | ||
142 | err_init: | ||
143 | tegra_bo_destroy(drm, bo); | ||
144 | err_dma: | ||
145 | kfree(bo); | ||
146 | |||
147 | return ERR_PTR(err); | ||
148 | |||
149 | } | ||
150 | |||
151 | struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, | ||
152 | struct drm_device *drm, | ||
153 | unsigned int size, | ||
154 | unsigned int *handle) | ||
155 | { | ||
156 | struct tegra_bo *bo; | ||
157 | int ret; | ||
158 | |||
159 | bo = tegra_bo_create(drm, size); | ||
160 | if (IS_ERR(bo)) | ||
161 | return bo; | ||
162 | |||
163 | ret = drm_gem_handle_create(file, &bo->gem, handle); | ||
164 | if (ret) | ||
165 | goto err; | ||
166 | |||
167 | drm_gem_object_unreference_unlocked(&bo->gem); | ||
168 | |||
169 | return bo; | ||
170 | |||
171 | err: | ||
172 | tegra_bo_free_object(&bo->gem); | ||
173 | return ERR_PTR(ret); | ||
174 | } | ||
175 | |||
176 | void tegra_bo_free_object(struct drm_gem_object *gem) | ||
177 | { | ||
178 | struct tegra_bo *bo = to_tegra_bo(gem); | ||
179 | |||
180 | drm_gem_free_mmap_offset(gem); | ||
181 | |||
182 | drm_gem_object_release(gem); | ||
183 | tegra_bo_destroy(gem->dev, bo); | ||
184 | |||
185 | kfree(bo); | ||
186 | } | ||
187 | |||
188 | int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, | ||
189 | struct drm_mode_create_dumb *args) | ||
190 | { | ||
191 | int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); | ||
192 | struct tegra_bo *bo; | ||
193 | |||
194 | if (args->pitch < min_pitch) | ||
195 | args->pitch = min_pitch; | ||
196 | |||
197 | if (args->size < args->pitch * args->height) | ||
198 | args->size = args->pitch * args->height; | ||
199 | |||
200 | bo = tegra_bo_create_with_handle(file, drm, args->size, | ||
201 | &args->handle); | ||
202 | if (IS_ERR(bo)) | ||
203 | return PTR_ERR(bo); | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, | ||
209 | uint32_t handle, uint64_t *offset) | ||
210 | { | ||
211 | struct drm_gem_object *gem; | ||
212 | struct tegra_bo *bo; | ||
213 | |||
214 | mutex_lock(&drm->struct_mutex); | ||
215 | |||
216 | gem = drm_gem_object_lookup(drm, file, handle); | ||
217 | if (!gem) { | ||
218 | dev_err(drm->dev, "failed to lookup GEM object\n"); | ||
219 | mutex_unlock(&drm->struct_mutex); | ||
220 | return -EINVAL; | ||
221 | } | ||
222 | |||
223 | bo = to_tegra_bo(gem); | ||
224 | |||
225 | *offset = drm_vma_node_offset_addr(&bo->gem.vma_node); | ||
226 | |||
227 | drm_gem_object_unreference(gem); | ||
228 | |||
229 | mutex_unlock(&drm->struct_mutex); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | const struct vm_operations_struct tegra_bo_vm_ops = { | ||
235 | .open = drm_gem_vm_open, | ||
236 | .close = drm_gem_vm_close, | ||
237 | }; | ||
238 | |||
239 | int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) | ||
240 | { | ||
241 | struct drm_gem_object *gem; | ||
242 | struct tegra_bo *bo; | ||
243 | int ret; | ||
244 | |||
245 | ret = drm_gem_mmap(file, vma); | ||
246 | if (ret) | ||
247 | return ret; | ||
248 | |||
249 | gem = vma->vm_private_data; | ||
250 | bo = to_tegra_bo(gem); | ||
251 | |||
252 | ret = remap_pfn_range(vma, vma->vm_start, bo->paddr >> PAGE_SHIFT, | ||
253 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
254 | if (ret) | ||
255 | drm_gem_vm_close(vma); | ||
256 | |||
257 | return ret; | ||
258 | } | ||
diff --git a/drivers/gpu/host1x/drm/gem.h b/drivers/gpu/host1x/drm/gem.h deleted file mode 100644 index 492533a2dacb..000000000000 --- a/drivers/gpu/host1x/drm/gem.h +++ /dev/null | |||
@@ -1,56 +0,0 @@ | |||
1 | /* | ||
2 | * Tegra host1x GEM implementation | ||
3 | * | ||
4 | * Copyright (c) 2012-2013, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef __HOST1X_GEM_H | ||
20 | #define __HOST1X_GEM_H | ||
21 | |||
22 | #include <drm/drm.h> | ||
23 | #include <drm/drmP.h> | ||
24 | |||
25 | #include "host1x_bo.h" | ||
26 | |||
27 | struct tegra_bo { | ||
28 | struct drm_gem_object gem; | ||
29 | struct host1x_bo base; | ||
30 | dma_addr_t paddr; | ||
31 | void *vaddr; | ||
32 | }; | ||
33 | |||
34 | static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem) | ||
35 | { | ||
36 | return container_of(gem, struct tegra_bo, gem); | ||
37 | } | ||
38 | |||
39 | extern const struct host1x_bo_ops tegra_bo_ops; | ||
40 | |||
41 | struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size); | ||
42 | struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, | ||
43 | struct drm_device *drm, | ||
44 | unsigned int size, | ||
45 | unsigned int *handle); | ||
46 | void tegra_bo_free_object(struct drm_gem_object *gem); | ||
47 | int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, | ||
48 | struct drm_mode_create_dumb *args); | ||
49 | int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, | ||
50 | uint32_t handle, uint64_t *offset); | ||
51 | |||
52 | int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); | ||
53 | |||
54 | extern const struct vm_operations_struct tegra_bo_vm_ops; | ||
55 | |||
56 | #endif | ||
diff --git a/drivers/gpu/host1x/drm/gr2d.c b/drivers/gpu/host1x/drm/gr2d.c deleted file mode 100644 index 27ffcf15a4b4..000000000000 --- a/drivers/gpu/host1x/drm/gr2d.c +++ /dev/null | |||
@@ -1,343 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/host/gr2d/gr2d.c | ||
3 | * | ||
4 | * Tegra Graphics 2D | ||
5 | * | ||
6 | * Copyright (c) 2012-2013, NVIDIA Corporation. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #include <linux/export.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_device.h> | ||
24 | #include <linux/clk.h> | ||
25 | |||
26 | #include "channel.h" | ||
27 | #include "drm.h" | ||
28 | #include "gem.h" | ||
29 | #include "job.h" | ||
30 | #include "host1x.h" | ||
31 | #include "host1x_bo.h" | ||
32 | #include "host1x_client.h" | ||
33 | #include "syncpt.h" | ||
34 | |||
35 | struct gr2d { | ||
36 | struct host1x_client client; | ||
37 | struct clk *clk; | ||
38 | struct host1x_channel *channel; | ||
39 | unsigned long *addr_regs; | ||
40 | }; | ||
41 | |||
42 | static inline struct gr2d *to_gr2d(struct host1x_client *client) | ||
43 | { | ||
44 | return container_of(client, struct gr2d, client); | ||
45 | } | ||
46 | |||
47 | static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 reg); | ||
48 | |||
49 | static int gr2d_client_init(struct host1x_client *client, | ||
50 | struct drm_device *drm) | ||
51 | { | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static int gr2d_client_exit(struct host1x_client *client) | ||
56 | { | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int gr2d_open_channel(struct host1x_client *client, | ||
61 | struct host1x_drm_context *context) | ||
62 | { | ||
63 | struct gr2d *gr2d = to_gr2d(client); | ||
64 | |||
65 | context->channel = host1x_channel_get(gr2d->channel); | ||
66 | |||
67 | if (!context->channel) | ||
68 | return -ENOMEM; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static void gr2d_close_channel(struct host1x_drm_context *context) | ||
74 | { | ||
75 | host1x_channel_put(context->channel); | ||
76 | } | ||
77 | |||
78 | static struct host1x_bo *host1x_bo_lookup(struct drm_device *drm, | ||
79 | struct drm_file *file, | ||
80 | u32 handle) | ||
81 | { | ||
82 | struct drm_gem_object *gem; | ||
83 | struct tegra_bo *bo; | ||
84 | |||
85 | gem = drm_gem_object_lookup(drm, file, handle); | ||
86 | if (!gem) | ||
87 | return NULL; | ||
88 | |||
89 | mutex_lock(&drm->struct_mutex); | ||
90 | drm_gem_object_unreference(gem); | ||
91 | mutex_unlock(&drm->struct_mutex); | ||
92 | |||
93 | bo = to_tegra_bo(gem); | ||
94 | return &bo->base; | ||
95 | } | ||
96 | |||
97 | static int gr2d_submit(struct host1x_drm_context *context, | ||
98 | struct drm_tegra_submit *args, struct drm_device *drm, | ||
99 | struct drm_file *file) | ||
100 | { | ||
101 | struct host1x_job *job; | ||
102 | unsigned int num_cmdbufs = args->num_cmdbufs; | ||
103 | unsigned int num_relocs = args->num_relocs; | ||
104 | unsigned int num_waitchks = args->num_waitchks; | ||
105 | struct drm_tegra_cmdbuf __user *cmdbufs = | ||
106 | (void * __user)(uintptr_t)args->cmdbufs; | ||
107 | struct drm_tegra_reloc __user *relocs = | ||
108 | (void * __user)(uintptr_t)args->relocs; | ||
109 | struct drm_tegra_waitchk __user *waitchks = | ||
110 | (void * __user)(uintptr_t)args->waitchks; | ||
111 | struct drm_tegra_syncpt syncpt; | ||
112 | int err; | ||
113 | |||
114 | /* We don't yet support other than one syncpt_incr struct per submit */ | ||
115 | if (args->num_syncpts != 1) | ||
116 | return -EINVAL; | ||
117 | |||
118 | job = host1x_job_alloc(context->channel, args->num_cmdbufs, | ||
119 | args->num_relocs, args->num_waitchks); | ||
120 | if (!job) | ||
121 | return -ENOMEM; | ||
122 | |||
123 | job->num_relocs = args->num_relocs; | ||
124 | job->num_waitchk = args->num_waitchks; | ||
125 | job->client = (u32)args->context; | ||
126 | job->class = context->client->class; | ||
127 | job->serialize = true; | ||
128 | |||
129 | while (num_cmdbufs) { | ||
130 | struct drm_tegra_cmdbuf cmdbuf; | ||
131 | struct host1x_bo *bo; | ||
132 | |||
133 | err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf)); | ||
134 | if (err) | ||
135 | goto fail; | ||
136 | |||
137 | bo = host1x_bo_lookup(drm, file, cmdbuf.handle); | ||
138 | if (!bo) { | ||
139 | err = -ENOENT; | ||
140 | goto fail; | ||
141 | } | ||
142 | |||
143 | host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset); | ||
144 | num_cmdbufs--; | ||
145 | cmdbufs++; | ||
146 | } | ||
147 | |||
148 | err = copy_from_user(job->relocarray, relocs, | ||
149 | sizeof(*relocs) * num_relocs); | ||
150 | if (err) | ||
151 | goto fail; | ||
152 | |||
153 | while (num_relocs--) { | ||
154 | struct host1x_reloc *reloc = &job->relocarray[num_relocs]; | ||
155 | struct host1x_bo *cmdbuf, *target; | ||
156 | |||
157 | cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf); | ||
158 | target = host1x_bo_lookup(drm, file, (u32)reloc->target); | ||
159 | |||
160 | reloc->cmdbuf = cmdbuf; | ||
161 | reloc->target = target; | ||
162 | |||
163 | if (!reloc->target || !reloc->cmdbuf) { | ||
164 | err = -ENOENT; | ||
165 | goto fail; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | err = copy_from_user(job->waitchk, waitchks, | ||
170 | sizeof(*waitchks) * num_waitchks); | ||
171 | if (err) | ||
172 | goto fail; | ||
173 | |||
174 | err = copy_from_user(&syncpt, (void * __user)(uintptr_t)args->syncpts, | ||
175 | sizeof(syncpt)); | ||
176 | if (err) | ||
177 | goto fail; | ||
178 | |||
179 | job->syncpt_id = syncpt.id; | ||
180 | job->syncpt_incrs = syncpt.incrs; | ||
181 | job->timeout = 10000; | ||
182 | job->is_addr_reg = gr2d_is_addr_reg; | ||
183 | |||
184 | if (args->timeout && args->timeout < 10000) | ||
185 | job->timeout = args->timeout; | ||
186 | |||
187 | err = host1x_job_pin(job, context->client->dev); | ||
188 | if (err) | ||
189 | goto fail; | ||
190 | |||
191 | err = host1x_job_submit(job); | ||
192 | if (err) | ||
193 | goto fail_submit; | ||
194 | |||
195 | args->fence = job->syncpt_end; | ||
196 | |||
197 | host1x_job_put(job); | ||
198 | return 0; | ||
199 | |||
200 | fail_submit: | ||
201 | host1x_job_unpin(job); | ||
202 | fail: | ||
203 | host1x_job_put(job); | ||
204 | return err; | ||
205 | } | ||
206 | |||
207 | static struct host1x_client_ops gr2d_client_ops = { | ||
208 | .drm_init = gr2d_client_init, | ||
209 | .drm_exit = gr2d_client_exit, | ||
210 | .open_channel = gr2d_open_channel, | ||
211 | .close_channel = gr2d_close_channel, | ||
212 | .submit = gr2d_submit, | ||
213 | }; | ||
214 | |||
215 | static void gr2d_init_addr_reg_map(struct device *dev, struct gr2d *gr2d) | ||
216 | { | ||
217 | const u32 gr2d_addr_regs[] = {0x1a, 0x1b, 0x26, 0x2b, 0x2c, 0x2d, 0x31, | ||
218 | 0x32, 0x48, 0x49, 0x4a, 0x4b, 0x4c}; | ||
219 | unsigned long *bitmap; | ||
220 | int i; | ||
221 | |||
222 | bitmap = devm_kzalloc(dev, DIV_ROUND_UP(256, BITS_PER_BYTE), | ||
223 | GFP_KERNEL); | ||
224 | |||
225 | for (i = 0; i < ARRAY_SIZE(gr2d_addr_regs); ++i) { | ||
226 | u32 reg = gr2d_addr_regs[i]; | ||
227 | bitmap[BIT_WORD(reg)] |= BIT_MASK(reg); | ||
228 | } | ||
229 | |||
230 | gr2d->addr_regs = bitmap; | ||
231 | } | ||
232 | |||
233 | static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 reg) | ||
234 | { | ||
235 | struct gr2d *gr2d = dev_get_drvdata(dev); | ||
236 | |||
237 | switch (class) { | ||
238 | case HOST1X_CLASS_HOST1X: | ||
239 | return reg == 0x2b; | ||
240 | case HOST1X_CLASS_GR2D: | ||
241 | case HOST1X_CLASS_GR2D_SB: | ||
242 | reg &= 0xff; | ||
243 | if (gr2d->addr_regs[BIT_WORD(reg)] & BIT_MASK(reg)) | ||
244 | return 1; | ||
245 | default: | ||
246 | return 0; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | static const struct of_device_id gr2d_match[] = { | ||
251 | { .compatible = "nvidia,tegra30-gr2d" }, | ||
252 | { .compatible = "nvidia,tegra20-gr2d" }, | ||
253 | { }, | ||
254 | }; | ||
255 | |||
256 | static int gr2d_probe(struct platform_device *pdev) | ||
257 | { | ||
258 | struct device *dev = &pdev->dev; | ||
259 | struct host1x_drm *host1x = host1x_get_drm_data(dev->parent); | ||
260 | int err; | ||
261 | struct gr2d *gr2d = NULL; | ||
262 | struct host1x_syncpt **syncpts; | ||
263 | |||
264 | gr2d = devm_kzalloc(dev, sizeof(*gr2d), GFP_KERNEL); | ||
265 | if (!gr2d) | ||
266 | return -ENOMEM; | ||
267 | |||
268 | syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); | ||
269 | if (!syncpts) | ||
270 | return -ENOMEM; | ||
271 | |||
272 | gr2d->clk = devm_clk_get(dev, NULL); | ||
273 | if (IS_ERR(gr2d->clk)) { | ||
274 | dev_err(dev, "cannot get clock\n"); | ||
275 | return PTR_ERR(gr2d->clk); | ||
276 | } | ||
277 | |||
278 | err = clk_prepare_enable(gr2d->clk); | ||
279 | if (err) { | ||
280 | dev_err(dev, "cannot turn on clock\n"); | ||
281 | return err; | ||
282 | } | ||
283 | |||
284 | gr2d->channel = host1x_channel_request(dev); | ||
285 | if (!gr2d->channel) | ||
286 | return -ENOMEM; | ||
287 | |||
288 | *syncpts = host1x_syncpt_request(dev, false); | ||
289 | if (!(*syncpts)) { | ||
290 | host1x_channel_free(gr2d->channel); | ||
291 | return -ENOMEM; | ||
292 | } | ||
293 | |||
294 | gr2d->client.ops = &gr2d_client_ops; | ||
295 | gr2d->client.dev = dev; | ||
296 | gr2d->client.class = HOST1X_CLASS_GR2D; | ||
297 | gr2d->client.syncpts = syncpts; | ||
298 | gr2d->client.num_syncpts = 1; | ||
299 | |||
300 | err = host1x_register_client(host1x, &gr2d->client); | ||
301 | if (err < 0) { | ||
302 | dev_err(dev, "failed to register host1x client: %d\n", err); | ||
303 | return err; | ||
304 | } | ||
305 | |||
306 | gr2d_init_addr_reg_map(dev, gr2d); | ||
307 | |||
308 | platform_set_drvdata(pdev, gr2d); | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static int __exit gr2d_remove(struct platform_device *pdev) | ||
314 | { | ||
315 | struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent); | ||
316 | struct gr2d *gr2d = platform_get_drvdata(pdev); | ||
317 | unsigned int i; | ||
318 | int err; | ||
319 | |||
320 | err = host1x_unregister_client(host1x, &gr2d->client); | ||
321 | if (err < 0) { | ||
322 | dev_err(&pdev->dev, "failed to unregister client: %d\n", err); | ||
323 | return err; | ||
324 | } | ||
325 | |||
326 | for (i = 0; i < gr2d->client.num_syncpts; i++) | ||
327 | host1x_syncpt_free(gr2d->client.syncpts[i]); | ||
328 | |||
329 | host1x_channel_free(gr2d->channel); | ||
330 | clk_disable_unprepare(gr2d->clk); | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | struct platform_driver tegra_gr2d_driver = { | ||
336 | .probe = gr2d_probe, | ||
337 | .remove = __exit_p(gr2d_remove), | ||
338 | .driver = { | ||
339 | .owner = THIS_MODULE, | ||
340 | .name = "gr2d", | ||
341 | .of_match_table = gr2d_match, | ||
342 | } | ||
343 | }; | ||
diff --git a/drivers/gpu/host1x/drm/hdmi.c b/drivers/gpu/host1x/drm/hdmi.c deleted file mode 100644 index 644d95c7d489..000000000000 --- a/drivers/gpu/host1x/drm/hdmi.c +++ /dev/null | |||
@@ -1,1304 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Avionic Design GmbH | ||
3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/debugfs.h> | ||
12 | #include <linux/gpio.h> | ||
13 | #include <linux/hdmi.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/regulator/consumer.h> | ||
18 | #include <linux/clk/tegra.h> | ||
19 | |||
20 | #include <drm/drm_edid.h> | ||
21 | |||
22 | #include "hdmi.h" | ||
23 | #include "drm.h" | ||
24 | #include "dc.h" | ||
25 | #include "host1x_client.h" | ||
26 | |||
27 | struct tegra_hdmi { | ||
28 | struct host1x_client client; | ||
29 | struct tegra_output output; | ||
30 | struct device *dev; | ||
31 | |||
32 | struct regulator *vdd; | ||
33 | struct regulator *pll; | ||
34 | |||
35 | void __iomem *regs; | ||
36 | unsigned int irq; | ||
37 | |||
38 | struct clk *clk_parent; | ||
39 | struct clk *clk; | ||
40 | |||
41 | unsigned int audio_source; | ||
42 | unsigned int audio_freq; | ||
43 | bool stereo; | ||
44 | bool dvi; | ||
45 | |||
46 | struct drm_info_list *debugfs_files; | ||
47 | struct drm_minor *minor; | ||
48 | struct dentry *debugfs; | ||
49 | }; | ||
50 | |||
51 | static inline struct tegra_hdmi * | ||
52 | host1x_client_to_hdmi(struct host1x_client *client) | ||
53 | { | ||
54 | return container_of(client, struct tegra_hdmi, client); | ||
55 | } | ||
56 | |||
57 | static inline struct tegra_hdmi *to_hdmi(struct tegra_output *output) | ||
58 | { | ||
59 | return container_of(output, struct tegra_hdmi, output); | ||
60 | } | ||
61 | |||
62 | #define HDMI_AUDIOCLK_FREQ 216000000 | ||
63 | #define HDMI_REKEY_DEFAULT 56 | ||
64 | |||
65 | enum { | ||
66 | AUTO = 0, | ||
67 | SPDIF, | ||
68 | HDA, | ||
69 | }; | ||
70 | |||
71 | static inline unsigned long tegra_hdmi_readl(struct tegra_hdmi *hdmi, | ||
72 | unsigned long reg) | ||
73 | { | ||
74 | return readl(hdmi->regs + (reg << 2)); | ||
75 | } | ||
76 | |||
77 | static inline void tegra_hdmi_writel(struct tegra_hdmi *hdmi, unsigned long val, | ||
78 | unsigned long reg) | ||
79 | { | ||
80 | writel(val, hdmi->regs + (reg << 2)); | ||
81 | } | ||
82 | |||
83 | struct tegra_hdmi_audio_config { | ||
84 | unsigned int pclk; | ||
85 | unsigned int n; | ||
86 | unsigned int cts; | ||
87 | unsigned int aval; | ||
88 | }; | ||
89 | |||
90 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_32k[] = { | ||
91 | { 25200000, 4096, 25200, 24000 }, | ||
92 | { 27000000, 4096, 27000, 24000 }, | ||
93 | { 74250000, 4096, 74250, 24000 }, | ||
94 | { 148500000, 4096, 148500, 24000 }, | ||
95 | { 0, 0, 0, 0 }, | ||
96 | }; | ||
97 | |||
98 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_44_1k[] = { | ||
99 | { 25200000, 5880, 26250, 25000 }, | ||
100 | { 27000000, 5880, 28125, 25000 }, | ||
101 | { 74250000, 4704, 61875, 20000 }, | ||
102 | { 148500000, 4704, 123750, 20000 }, | ||
103 | { 0, 0, 0, 0 }, | ||
104 | }; | ||
105 | |||
106 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_48k[] = { | ||
107 | { 25200000, 6144, 25200, 24000 }, | ||
108 | { 27000000, 6144, 27000, 24000 }, | ||
109 | { 74250000, 6144, 74250, 24000 }, | ||
110 | { 148500000, 6144, 148500, 24000 }, | ||
111 | { 0, 0, 0, 0 }, | ||
112 | }; | ||
113 | |||
114 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_88_2k[] = { | ||
115 | { 25200000, 11760, 26250, 25000 }, | ||
116 | { 27000000, 11760, 28125, 25000 }, | ||
117 | { 74250000, 9408, 61875, 20000 }, | ||
118 | { 148500000, 9408, 123750, 20000 }, | ||
119 | { 0, 0, 0, 0 }, | ||
120 | }; | ||
121 | |||
122 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_96k[] = { | ||
123 | { 25200000, 12288, 25200, 24000 }, | ||
124 | { 27000000, 12288, 27000, 24000 }, | ||
125 | { 74250000, 12288, 74250, 24000 }, | ||
126 | { 148500000, 12288, 148500, 24000 }, | ||
127 | { 0, 0, 0, 0 }, | ||
128 | }; | ||
129 | |||
130 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_176_4k[] = { | ||
131 | { 25200000, 23520, 26250, 25000 }, | ||
132 | { 27000000, 23520, 28125, 25000 }, | ||
133 | { 74250000, 18816, 61875, 20000 }, | ||
134 | { 148500000, 18816, 123750, 20000 }, | ||
135 | { 0, 0, 0, 0 }, | ||
136 | }; | ||
137 | |||
138 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_192k[] = { | ||
139 | { 25200000, 24576, 25200, 24000 }, | ||
140 | { 27000000, 24576, 27000, 24000 }, | ||
141 | { 74250000, 24576, 74250, 24000 }, | ||
142 | { 148500000, 24576, 148500, 24000 }, | ||
143 | { 0, 0, 0, 0 }, | ||
144 | }; | ||
145 | |||
146 | struct tmds_config { | ||
147 | unsigned int pclk; | ||
148 | u32 pll0; | ||
149 | u32 pll1; | ||
150 | u32 pe_current; | ||
151 | u32 drive_current; | ||
152 | }; | ||
153 | |||
154 | static const struct tmds_config tegra2_tmds_config[] = { | ||
155 | { /* slow pixel clock modes */ | ||
156 | .pclk = 27000000, | ||
157 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | | ||
158 | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(0) | | ||
159 | SOR_PLL_TX_REG_LOAD(3), | ||
160 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE, | ||
161 | .pe_current = PE_CURRENT0(PE_CURRENT_0_0_mA) | | ||
162 | PE_CURRENT1(PE_CURRENT_0_0_mA) | | ||
163 | PE_CURRENT2(PE_CURRENT_0_0_mA) | | ||
164 | PE_CURRENT3(PE_CURRENT_0_0_mA), | ||
165 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) | | ||
166 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) | | ||
167 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) | | ||
168 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA), | ||
169 | }, | ||
170 | { /* high pixel clock modes */ | ||
171 | .pclk = UINT_MAX, | ||
172 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | | ||
173 | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(1) | | ||
174 | SOR_PLL_TX_REG_LOAD(3), | ||
175 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, | ||
176 | .pe_current = PE_CURRENT0(PE_CURRENT_6_0_mA) | | ||
177 | PE_CURRENT1(PE_CURRENT_6_0_mA) | | ||
178 | PE_CURRENT2(PE_CURRENT_6_0_mA) | | ||
179 | PE_CURRENT3(PE_CURRENT_6_0_mA), | ||
180 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) | | ||
181 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) | | ||
182 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) | | ||
183 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA), | ||
184 | }, | ||
185 | }; | ||
186 | |||
187 | static const struct tmds_config tegra3_tmds_config[] = { | ||
188 | { /* 480p modes */ | ||
189 | .pclk = 27000000, | ||
190 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | | ||
191 | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(0) | | ||
192 | SOR_PLL_TX_REG_LOAD(0), | ||
193 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE, | ||
194 | .pe_current = PE_CURRENT0(PE_CURRENT_0_0_mA) | | ||
195 | PE_CURRENT1(PE_CURRENT_0_0_mA) | | ||
196 | PE_CURRENT2(PE_CURRENT_0_0_mA) | | ||
197 | PE_CURRENT3(PE_CURRENT_0_0_mA), | ||
198 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) | | ||
199 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) | | ||
200 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) | | ||
201 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA), | ||
202 | }, { /* 720p modes */ | ||
203 | .pclk = 74250000, | ||
204 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | | ||
205 | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(1) | | ||
206 | SOR_PLL_TX_REG_LOAD(0), | ||
207 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, | ||
208 | .pe_current = PE_CURRENT0(PE_CURRENT_5_0_mA) | | ||
209 | PE_CURRENT1(PE_CURRENT_5_0_mA) | | ||
210 | PE_CURRENT2(PE_CURRENT_5_0_mA) | | ||
211 | PE_CURRENT3(PE_CURRENT_5_0_mA), | ||
212 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) | | ||
213 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) | | ||
214 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) | | ||
215 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA), | ||
216 | }, { /* 1080p modes */ | ||
217 | .pclk = UINT_MAX, | ||
218 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | | ||
219 | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(3) | | ||
220 | SOR_PLL_TX_REG_LOAD(0), | ||
221 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, | ||
222 | .pe_current = PE_CURRENT0(PE_CURRENT_5_0_mA) | | ||
223 | PE_CURRENT1(PE_CURRENT_5_0_mA) | | ||
224 | PE_CURRENT2(PE_CURRENT_5_0_mA) | | ||
225 | PE_CURRENT3(PE_CURRENT_5_0_mA), | ||
226 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) | | ||
227 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) | | ||
228 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) | | ||
229 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA), | ||
230 | }, | ||
231 | }; | ||
232 | |||
233 | static const struct tegra_hdmi_audio_config * | ||
234 | tegra_hdmi_get_audio_config(unsigned int audio_freq, unsigned int pclk) | ||
235 | { | ||
236 | const struct tegra_hdmi_audio_config *table; | ||
237 | |||
238 | switch (audio_freq) { | ||
239 | case 32000: | ||
240 | table = tegra_hdmi_audio_32k; | ||
241 | break; | ||
242 | |||
243 | case 44100: | ||
244 | table = tegra_hdmi_audio_44_1k; | ||
245 | break; | ||
246 | |||
247 | case 48000: | ||
248 | table = tegra_hdmi_audio_48k; | ||
249 | break; | ||
250 | |||
251 | case 88200: | ||
252 | table = tegra_hdmi_audio_88_2k; | ||
253 | break; | ||
254 | |||
255 | case 96000: | ||
256 | table = tegra_hdmi_audio_96k; | ||
257 | break; | ||
258 | |||
259 | case 176400: | ||
260 | table = tegra_hdmi_audio_176_4k; | ||
261 | break; | ||
262 | |||
263 | case 192000: | ||
264 | table = tegra_hdmi_audio_192k; | ||
265 | break; | ||
266 | |||
267 | default: | ||
268 | return NULL; | ||
269 | } | ||
270 | |||
271 | while (table->pclk) { | ||
272 | if (table->pclk == pclk) | ||
273 | return table; | ||
274 | |||
275 | table++; | ||
276 | } | ||
277 | |||
278 | return NULL; | ||
279 | } | ||
280 | |||
281 | static void tegra_hdmi_setup_audio_fs_tables(struct tegra_hdmi *hdmi) | ||
282 | { | ||
283 | const unsigned int freqs[] = { | ||
284 | 32000, 44100, 48000, 88200, 96000, 176400, 192000 | ||
285 | }; | ||
286 | unsigned int i; | ||
287 | |||
288 | for (i = 0; i < ARRAY_SIZE(freqs); i++) { | ||
289 | unsigned int f = freqs[i]; | ||
290 | unsigned int eight_half; | ||
291 | unsigned long value; | ||
292 | unsigned int delta; | ||
293 | |||
294 | if (f > 96000) | ||
295 | delta = 2; | ||
296 | else if (f > 480000) | ||
297 | delta = 6; | ||
298 | else | ||
299 | delta = 9; | ||
300 | |||
301 | eight_half = (8 * HDMI_AUDIOCLK_FREQ) / (f * 128); | ||
302 | value = AUDIO_FS_LOW(eight_half - delta) | | ||
303 | AUDIO_FS_HIGH(eight_half + delta); | ||
304 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_FS(i)); | ||
305 | } | ||
306 | } | ||
307 | |||
308 | static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk) | ||
309 | { | ||
310 | struct device_node *node = hdmi->dev->of_node; | ||
311 | const struct tegra_hdmi_audio_config *config; | ||
312 | unsigned int offset = 0; | ||
313 | unsigned long value; | ||
314 | |||
315 | switch (hdmi->audio_source) { | ||
316 | case HDA: | ||
317 | value = AUDIO_CNTRL0_SOURCE_SELECT_HDAL; | ||
318 | break; | ||
319 | |||
320 | case SPDIF: | ||
321 | value = AUDIO_CNTRL0_SOURCE_SELECT_SPDIF; | ||
322 | break; | ||
323 | |||
324 | default: | ||
325 | value = AUDIO_CNTRL0_SOURCE_SELECT_AUTO; | ||
326 | break; | ||
327 | } | ||
328 | |||
329 | if (of_device_is_compatible(node, "nvidia,tegra30-hdmi")) { | ||
330 | value |= AUDIO_CNTRL0_ERROR_TOLERANCE(6) | | ||
331 | AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0); | ||
332 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_CNTRL0); | ||
333 | } else { | ||
334 | value |= AUDIO_CNTRL0_INJECT_NULLSMPL; | ||
335 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_AUDIO_CNTRL0); | ||
336 | |||
337 | value = AUDIO_CNTRL0_ERROR_TOLERANCE(6) | | ||
338 | AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0); | ||
339 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_CNTRL0); | ||
340 | } | ||
341 | |||
342 | config = tegra_hdmi_get_audio_config(hdmi->audio_freq, pclk); | ||
343 | if (!config) { | ||
344 | dev_err(hdmi->dev, "cannot set audio to %u at %u pclk\n", | ||
345 | hdmi->audio_freq, pclk); | ||
346 | return -EINVAL; | ||
347 | } | ||
348 | |||
349 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_HDMI_ACR_CTRL); | ||
350 | |||
351 | value = AUDIO_N_RESETF | AUDIO_N_GENERATE_ALTERNATE | | ||
352 | AUDIO_N_VALUE(config->n - 1); | ||
353 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N); | ||
354 | |||
355 | tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config->n) | ACR_ENABLE, | ||
356 | HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); | ||
357 | |||
358 | value = ACR_SUBPACK_CTS(config->cts); | ||
359 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); | ||
360 | |||
361 | value = SPARE_HW_CTS | SPARE_FORCE_SW_CTS | SPARE_CTS_RESET_VAL(1); | ||
362 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_SPARE); | ||
363 | |||
364 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_AUDIO_N); | ||
365 | value &= ~AUDIO_N_RESETF; | ||
366 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N); | ||
367 | |||
368 | if (of_device_is_compatible(node, "nvidia,tegra30-hdmi")) { | ||
369 | switch (hdmi->audio_freq) { | ||
370 | case 32000: | ||
371 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320; | ||
372 | break; | ||
373 | |||
374 | case 44100: | ||
375 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441; | ||
376 | break; | ||
377 | |||
378 | case 48000: | ||
379 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480; | ||
380 | break; | ||
381 | |||
382 | case 88200: | ||
383 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882; | ||
384 | break; | ||
385 | |||
386 | case 96000: | ||
387 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960; | ||
388 | break; | ||
389 | |||
390 | case 176400: | ||
391 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764; | ||
392 | break; | ||
393 | |||
394 | case 192000: | ||
395 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920; | ||
396 | break; | ||
397 | } | ||
398 | |||
399 | tegra_hdmi_writel(hdmi, config->aval, offset); | ||
400 | } | ||
401 | |||
402 | tegra_hdmi_setup_audio_fs_tables(hdmi); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static inline unsigned long tegra_hdmi_subpack(const u8 *ptr, size_t size) | ||
408 | { | ||
409 | unsigned long value = 0; | ||
410 | size_t i; | ||
411 | |||
412 | for (i = size; i > 0; i--) | ||
413 | value = (value << 8) | ptr[i - 1]; | ||
414 | |||
415 | return value; | ||
416 | } | ||
417 | |||
418 | static void tegra_hdmi_write_infopack(struct tegra_hdmi *hdmi, const void *data, | ||
419 | size_t size) | ||
420 | { | ||
421 | const u8 *ptr = data; | ||
422 | unsigned long offset; | ||
423 | unsigned long value; | ||
424 | size_t i, j; | ||
425 | |||
426 | switch (ptr[0]) { | ||
427 | case HDMI_INFOFRAME_TYPE_AVI: | ||
428 | offset = HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER; | ||
429 | break; | ||
430 | |||
431 | case HDMI_INFOFRAME_TYPE_AUDIO: | ||
432 | offset = HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER; | ||
433 | break; | ||
434 | |||
435 | case HDMI_INFOFRAME_TYPE_VENDOR: | ||
436 | offset = HDMI_NV_PDISP_HDMI_GENERIC_HEADER; | ||
437 | break; | ||
438 | |||
439 | default: | ||
440 | dev_err(hdmi->dev, "unsupported infoframe type: %02x\n", | ||
441 | ptr[0]); | ||
442 | return; | ||
443 | } | ||
444 | |||
445 | value = INFOFRAME_HEADER_TYPE(ptr[0]) | | ||
446 | INFOFRAME_HEADER_VERSION(ptr[1]) | | ||
447 | INFOFRAME_HEADER_LEN(ptr[2]); | ||
448 | tegra_hdmi_writel(hdmi, value, offset); | ||
449 | offset++; | ||
450 | |||
451 | /* | ||
452 | * Each subpack contains 7 bytes, divided into: | ||
453 | * - subpack_low: bytes 0 - 3 | ||
454 | * - subpack_high: bytes 4 - 6 (with byte 7 padded to 0x00) | ||
455 | */ | ||
456 | for (i = 3, j = 0; i < size; i += 7, j += 8) { | ||
457 | size_t rem = size - i, num = min_t(size_t, rem, 4); | ||
458 | |||
459 | value = tegra_hdmi_subpack(&ptr[i], num); | ||
460 | tegra_hdmi_writel(hdmi, value, offset++); | ||
461 | |||
462 | num = min_t(size_t, rem - num, 3); | ||
463 | |||
464 | value = tegra_hdmi_subpack(&ptr[i + 4], num); | ||
465 | tegra_hdmi_writel(hdmi, value, offset++); | ||
466 | } | ||
467 | } | ||
468 | |||
469 | static void tegra_hdmi_setup_avi_infoframe(struct tegra_hdmi *hdmi, | ||
470 | struct drm_display_mode *mode) | ||
471 | { | ||
472 | struct hdmi_avi_infoframe frame; | ||
473 | u8 buffer[17]; | ||
474 | ssize_t err; | ||
475 | |||
476 | if (hdmi->dvi) { | ||
477 | tegra_hdmi_writel(hdmi, 0, | ||
478 | HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
479 | return; | ||
480 | } | ||
481 | |||
482 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); | ||
483 | if (err < 0) { | ||
484 | dev_err(hdmi->dev, "failed to setup AVI infoframe: %zd\n", err); | ||
485 | return; | ||
486 | } | ||
487 | |||
488 | err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); | ||
489 | if (err < 0) { | ||
490 | dev_err(hdmi->dev, "failed to pack AVI infoframe: %zd\n", err); | ||
491 | return; | ||
492 | } | ||
493 | |||
494 | tegra_hdmi_write_infopack(hdmi, buffer, err); | ||
495 | |||
496 | tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE, | ||
497 | HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
498 | } | ||
499 | |||
500 | static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi) | ||
501 | { | ||
502 | struct hdmi_audio_infoframe frame; | ||
503 | u8 buffer[14]; | ||
504 | ssize_t err; | ||
505 | |||
506 | if (hdmi->dvi) { | ||
507 | tegra_hdmi_writel(hdmi, 0, | ||
508 | HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
509 | return; | ||
510 | } | ||
511 | |||
512 | err = hdmi_audio_infoframe_init(&frame); | ||
513 | if (err < 0) { | ||
514 | dev_err(hdmi->dev, "failed to initialize audio infoframe: %d\n", | ||
515 | err); | ||
516 | return; | ||
517 | } | ||
518 | |||
519 | frame.channels = 2; | ||
520 | |||
521 | err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); | ||
522 | if (err < 0) { | ||
523 | dev_err(hdmi->dev, "failed to pack audio infoframe: %zd\n", | ||
524 | err); | ||
525 | return; | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * The audio infoframe has only one set of subpack registers, so the | ||
530 | * infoframe needs to be truncated. One set of subpack registers can | ||
531 | * contain 7 bytes. Including the 3 byte header only the first 10 | ||
532 | * bytes can be programmed. | ||
533 | */ | ||
534 | tegra_hdmi_write_infopack(hdmi, buffer, min(10, err)); | ||
535 | |||
536 | tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE, | ||
537 | HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
538 | } | ||
539 | |||
540 | static void tegra_hdmi_setup_stereo_infoframe(struct tegra_hdmi *hdmi) | ||
541 | { | ||
542 | struct hdmi_vendor_infoframe frame; | ||
543 | unsigned long value; | ||
544 | u8 buffer[10]; | ||
545 | ssize_t err; | ||
546 | |||
547 | if (!hdmi->stereo) { | ||
548 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
549 | value &= ~GENERIC_CTRL_ENABLE; | ||
550 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
551 | return; | ||
552 | } | ||
553 | |||
554 | hdmi_vendor_infoframe_init(&frame); | ||
555 | frame.s3d_struct = HDMI_3D_STRUCTURE_FRAME_PACKING; | ||
556 | |||
557 | err = hdmi_vendor_infoframe_pack(&frame, buffer, sizeof(buffer)); | ||
558 | if (err < 0) { | ||
559 | dev_err(hdmi->dev, "failed to pack vendor infoframe: %zd\n", | ||
560 | err); | ||
561 | return; | ||
562 | } | ||
563 | |||
564 | tegra_hdmi_write_infopack(hdmi, buffer, err); | ||
565 | |||
566 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
567 | value |= GENERIC_CTRL_ENABLE; | ||
568 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
569 | } | ||
570 | |||
571 | static void tegra_hdmi_setup_tmds(struct tegra_hdmi *hdmi, | ||
572 | const struct tmds_config *tmds) | ||
573 | { | ||
574 | unsigned long value; | ||
575 | |||
576 | tegra_hdmi_writel(hdmi, tmds->pll0, HDMI_NV_PDISP_SOR_PLL0); | ||
577 | tegra_hdmi_writel(hdmi, tmds->pll1, HDMI_NV_PDISP_SOR_PLL1); | ||
578 | tegra_hdmi_writel(hdmi, tmds->pe_current, HDMI_NV_PDISP_PE_CURRENT); | ||
579 | |||
580 | value = tmds->drive_current | DRIVE_CURRENT_FUSE_OVERRIDE; | ||
581 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT); | ||
582 | } | ||
583 | |||
584 | static int tegra_output_hdmi_enable(struct tegra_output *output) | ||
585 | { | ||
586 | unsigned int h_sync_width, h_front_porch, h_back_porch, i, rekey; | ||
587 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | ||
588 | struct drm_display_mode *mode = &dc->base.mode; | ||
589 | struct tegra_hdmi *hdmi = to_hdmi(output); | ||
590 | struct device_node *node = hdmi->dev->of_node; | ||
591 | unsigned int pulse_start, div82, pclk; | ||
592 | const struct tmds_config *tmds; | ||
593 | unsigned int num_tmds; | ||
594 | unsigned long value; | ||
595 | int retries = 1000; | ||
596 | int err; | ||
597 | |||
598 | pclk = mode->clock * 1000; | ||
599 | h_sync_width = mode->hsync_end - mode->hsync_start; | ||
600 | h_back_porch = mode->htotal - mode->hsync_end; | ||
601 | h_front_porch = mode->hsync_start - mode->hdisplay; | ||
602 | |||
603 | err = regulator_enable(hdmi->vdd); | ||
604 | if (err < 0) { | ||
605 | dev_err(hdmi->dev, "failed to enable VDD regulator: %d\n", err); | ||
606 | return err; | ||
607 | } | ||
608 | |||
609 | err = regulator_enable(hdmi->pll); | ||
610 | if (err < 0) { | ||
611 | dev_err(hdmi->dev, "failed to enable PLL regulator: %d\n", err); | ||
612 | return err; | ||
613 | } | ||
614 | |||
615 | /* | ||
616 | * This assumes that the display controller will divide its parent | ||
617 | * clock by 2 to generate the pixel clock. | ||
618 | */ | ||
619 | err = tegra_output_setup_clock(output, hdmi->clk, pclk * 2); | ||
620 | if (err < 0) { | ||
621 | dev_err(hdmi->dev, "failed to setup clock: %d\n", err); | ||
622 | return err; | ||
623 | } | ||
624 | |||
625 | err = clk_set_rate(hdmi->clk, pclk); | ||
626 | if (err < 0) | ||
627 | return err; | ||
628 | |||
629 | err = clk_enable(hdmi->clk); | ||
630 | if (err < 0) { | ||
631 | dev_err(hdmi->dev, "failed to enable clock: %d\n", err); | ||
632 | return err; | ||
633 | } | ||
634 | |||
635 | tegra_periph_reset_assert(hdmi->clk); | ||
636 | usleep_range(1000, 2000); | ||
637 | tegra_periph_reset_deassert(hdmi->clk); | ||
638 | |||
639 | tegra_dc_writel(dc, VSYNC_H_POSITION(1), | ||
640 | DC_DISP_DISP_TIMING_OPTIONS); | ||
641 | tegra_dc_writel(dc, DITHER_CONTROL_DISABLE | BASE_COLOR_SIZE888, | ||
642 | DC_DISP_DISP_COLOR_CONTROL); | ||
643 | |||
644 | /* video_preamble uses h_pulse2 */ | ||
645 | pulse_start = 1 + h_sync_width + h_back_porch - 10; | ||
646 | |||
647 | tegra_dc_writel(dc, H_PULSE_2_ENABLE, DC_DISP_DISP_SIGNAL_OPTIONS0); | ||
648 | |||
649 | value = PULSE_MODE_NORMAL | PULSE_POLARITY_HIGH | PULSE_QUAL_VACTIVE | | ||
650 | PULSE_LAST_END_A; | ||
651 | tegra_dc_writel(dc, value, DC_DISP_H_PULSE2_CONTROL); | ||
652 | |||
653 | value = PULSE_START(pulse_start) | PULSE_END(pulse_start + 8); | ||
654 | tegra_dc_writel(dc, value, DC_DISP_H_PULSE2_POSITION_A); | ||
655 | |||
656 | value = VSYNC_WINDOW_END(0x210) | VSYNC_WINDOW_START(0x200) | | ||
657 | VSYNC_WINDOW_ENABLE; | ||
658 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_VSYNC_WINDOW); | ||
659 | |||
660 | if (dc->pipe) | ||
661 | value = HDMI_SRC_DISPLAYB; | ||
662 | else | ||
663 | value = HDMI_SRC_DISPLAYA; | ||
664 | |||
665 | if ((mode->hdisplay == 720) && ((mode->vdisplay == 480) || | ||
666 | (mode->vdisplay == 576))) | ||
667 | tegra_hdmi_writel(hdmi, | ||
668 | value | ARM_VIDEO_RANGE_FULL, | ||
669 | HDMI_NV_PDISP_INPUT_CONTROL); | ||
670 | else | ||
671 | tegra_hdmi_writel(hdmi, | ||
672 | value | ARM_VIDEO_RANGE_LIMITED, | ||
673 | HDMI_NV_PDISP_INPUT_CONTROL); | ||
674 | |||
675 | div82 = clk_get_rate(hdmi->clk) / 1000000 * 4; | ||
676 | value = SOR_REFCLK_DIV_INT(div82 >> 2) | SOR_REFCLK_DIV_FRAC(div82); | ||
677 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_REFCLK); | ||
678 | |||
679 | if (!hdmi->dvi) { | ||
680 | err = tegra_hdmi_setup_audio(hdmi, pclk); | ||
681 | if (err < 0) | ||
682 | hdmi->dvi = true; | ||
683 | } | ||
684 | |||
685 | if (of_device_is_compatible(node, "nvidia,tegra20-hdmi")) { | ||
686 | /* | ||
687 | * TODO: add ELD support | ||
688 | */ | ||
689 | } | ||
690 | |||
691 | rekey = HDMI_REKEY_DEFAULT; | ||
692 | value = HDMI_CTRL_REKEY(rekey); | ||
693 | value |= HDMI_CTRL_MAX_AC_PACKET((h_sync_width + h_back_porch + | ||
694 | h_front_porch - rekey - 18) / 32); | ||
695 | |||
696 | if (!hdmi->dvi) | ||
697 | value |= HDMI_CTRL_ENABLE; | ||
698 | |||
699 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_CTRL); | ||
700 | |||
701 | if (hdmi->dvi) | ||
702 | tegra_hdmi_writel(hdmi, 0x0, | ||
703 | HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
704 | else | ||
705 | tegra_hdmi_writel(hdmi, GENERIC_CTRL_AUDIO, | ||
706 | HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
707 | |||
708 | tegra_hdmi_setup_avi_infoframe(hdmi, mode); | ||
709 | tegra_hdmi_setup_audio_infoframe(hdmi); | ||
710 | tegra_hdmi_setup_stereo_infoframe(hdmi); | ||
711 | |||
712 | /* TMDS CONFIG */ | ||
713 | if (of_device_is_compatible(node, "nvidia,tegra30-hdmi")) { | ||
714 | num_tmds = ARRAY_SIZE(tegra3_tmds_config); | ||
715 | tmds = tegra3_tmds_config; | ||
716 | } else { | ||
717 | num_tmds = ARRAY_SIZE(tegra2_tmds_config); | ||
718 | tmds = tegra2_tmds_config; | ||
719 | } | ||
720 | |||
721 | for (i = 0; i < num_tmds; i++) { | ||
722 | if (pclk <= tmds[i].pclk) { | ||
723 | tegra_hdmi_setup_tmds(hdmi, &tmds[i]); | ||
724 | break; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | tegra_hdmi_writel(hdmi, | ||
729 | SOR_SEQ_CTL_PU_PC(0) | | ||
730 | SOR_SEQ_PU_PC_ALT(0) | | ||
731 | SOR_SEQ_PD_PC(8) | | ||
732 | SOR_SEQ_PD_PC_ALT(8), | ||
733 | HDMI_NV_PDISP_SOR_SEQ_CTL); | ||
734 | |||
735 | value = SOR_SEQ_INST_WAIT_TIME(1) | | ||
736 | SOR_SEQ_INST_WAIT_UNITS_VSYNC | | ||
737 | SOR_SEQ_INST_HALT | | ||
738 | SOR_SEQ_INST_PIN_A_LOW | | ||
739 | SOR_SEQ_INST_PIN_B_LOW | | ||
740 | SOR_SEQ_INST_DRIVE_PWM_OUT_LO; | ||
741 | |||
742 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_SEQ_INST(0)); | ||
743 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_SEQ_INST(8)); | ||
744 | |||
745 | value = 0x1c800; | ||
746 | value &= ~SOR_CSTM_ROTCLK(~0); | ||
747 | value |= SOR_CSTM_ROTCLK(2); | ||
748 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_CSTM); | ||
749 | |||
750 | tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND); | ||
751 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
752 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
753 | |||
754 | /* start SOR */ | ||
755 | tegra_hdmi_writel(hdmi, | ||
756 | SOR_PWR_NORMAL_STATE_PU | | ||
757 | SOR_PWR_NORMAL_START_NORMAL | | ||
758 | SOR_PWR_SAFE_STATE_PD | | ||
759 | SOR_PWR_SETTING_NEW_TRIGGER, | ||
760 | HDMI_NV_PDISP_SOR_PWR); | ||
761 | tegra_hdmi_writel(hdmi, | ||
762 | SOR_PWR_NORMAL_STATE_PU | | ||
763 | SOR_PWR_NORMAL_START_NORMAL | | ||
764 | SOR_PWR_SAFE_STATE_PD | | ||
765 | SOR_PWR_SETTING_NEW_DONE, | ||
766 | HDMI_NV_PDISP_SOR_PWR); | ||
767 | |||
768 | do { | ||
769 | BUG_ON(--retries < 0); | ||
770 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PWR); | ||
771 | } while (value & SOR_PWR_SETTING_NEW_PENDING); | ||
772 | |||
773 | value = SOR_STATE_ASY_CRCMODE_COMPLETE | | ||
774 | SOR_STATE_ASY_OWNER_HEAD0 | | ||
775 | SOR_STATE_ASY_SUBOWNER_BOTH | | ||
776 | SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A | | ||
777 | SOR_STATE_ASY_DEPOL_POS; | ||
778 | |||
779 | /* setup sync polarities */ | ||
780 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
781 | value |= SOR_STATE_ASY_HSYNCPOL_POS; | ||
782 | |||
783 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
784 | value |= SOR_STATE_ASY_HSYNCPOL_NEG; | ||
785 | |||
786 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
787 | value |= SOR_STATE_ASY_VSYNCPOL_POS; | ||
788 | |||
789 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
790 | value |= SOR_STATE_ASY_VSYNCPOL_NEG; | ||
791 | |||
792 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_STATE2); | ||
793 | |||
794 | value = SOR_STATE_ASY_HEAD_OPMODE_AWAKE | SOR_STATE_ASY_ORMODE_NORMAL; | ||
795 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_STATE1); | ||
796 | |||
797 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0); | ||
798 | tegra_hdmi_writel(hdmi, SOR_STATE_UPDATE, HDMI_NV_PDISP_SOR_STATE0); | ||
799 | tegra_hdmi_writel(hdmi, value | SOR_STATE_ATTACHED, | ||
800 | HDMI_NV_PDISP_SOR_STATE1); | ||
801 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0); | ||
802 | |||
803 | tegra_dc_writel(dc, HDMI_ENABLE, DC_DISP_DISP_WIN_OPTIONS); | ||
804 | |||
805 | value = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | | ||
806 | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; | ||
807 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); | ||
808 | |||
809 | value = DISP_CTRL_MODE_C_DISPLAY; | ||
810 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); | ||
811 | |||
812 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
813 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
814 | |||
815 | /* TODO: add HDCP support */ | ||
816 | |||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | static int tegra_output_hdmi_disable(struct tegra_output *output) | ||
821 | { | ||
822 | struct tegra_hdmi *hdmi = to_hdmi(output); | ||
823 | |||
824 | tegra_periph_reset_assert(hdmi->clk); | ||
825 | clk_disable(hdmi->clk); | ||
826 | regulator_disable(hdmi->pll); | ||
827 | regulator_disable(hdmi->vdd); | ||
828 | |||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | static int tegra_output_hdmi_setup_clock(struct tegra_output *output, | ||
833 | struct clk *clk, unsigned long pclk) | ||
834 | { | ||
835 | struct tegra_hdmi *hdmi = to_hdmi(output); | ||
836 | struct clk *base; | ||
837 | int err; | ||
838 | |||
839 | err = clk_set_parent(clk, hdmi->clk_parent); | ||
840 | if (err < 0) { | ||
841 | dev_err(output->dev, "failed to set parent: %d\n", err); | ||
842 | return err; | ||
843 | } | ||
844 | |||
845 | base = clk_get_parent(hdmi->clk_parent); | ||
846 | |||
847 | /* | ||
848 | * This assumes that the parent clock is pll_d_out0 or pll_d2_out | ||
849 | * respectively, each of which divides the base pll_d by 2. | ||
850 | */ | ||
851 | err = clk_set_rate(base, pclk * 2); | ||
852 | if (err < 0) | ||
853 | dev_err(output->dev, | ||
854 | "failed to set base clock rate to %lu Hz\n", | ||
855 | pclk * 2); | ||
856 | |||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | static int tegra_output_hdmi_check_mode(struct tegra_output *output, | ||
861 | struct drm_display_mode *mode, | ||
862 | enum drm_mode_status *status) | ||
863 | { | ||
864 | struct tegra_hdmi *hdmi = to_hdmi(output); | ||
865 | unsigned long pclk = mode->clock * 1000; | ||
866 | struct clk *parent; | ||
867 | long err; | ||
868 | |||
869 | parent = clk_get_parent(hdmi->clk_parent); | ||
870 | |||
871 | err = clk_round_rate(parent, pclk * 4); | ||
872 | if (err < 0) | ||
873 | *status = MODE_NOCLOCK; | ||
874 | else | ||
875 | *status = MODE_OK; | ||
876 | |||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | static const struct tegra_output_ops hdmi_ops = { | ||
881 | .enable = tegra_output_hdmi_enable, | ||
882 | .disable = tegra_output_hdmi_disable, | ||
883 | .setup_clock = tegra_output_hdmi_setup_clock, | ||
884 | .check_mode = tegra_output_hdmi_check_mode, | ||
885 | }; | ||
886 | |||
887 | static int tegra_hdmi_show_regs(struct seq_file *s, void *data) | ||
888 | { | ||
889 | struct drm_info_node *node = s->private; | ||
890 | struct tegra_hdmi *hdmi = node->info_ent->data; | ||
891 | int err; | ||
892 | |||
893 | err = clk_enable(hdmi->clk); | ||
894 | if (err) | ||
895 | return err; | ||
896 | |||
897 | #define DUMP_REG(name) \ | ||
898 | seq_printf(s, "%-56s %#05x %08lx\n", #name, name, \ | ||
899 | tegra_hdmi_readl(hdmi, name)) | ||
900 | |||
901 | DUMP_REG(HDMI_CTXSW); | ||
902 | DUMP_REG(HDMI_NV_PDISP_SOR_STATE0); | ||
903 | DUMP_REG(HDMI_NV_PDISP_SOR_STATE1); | ||
904 | DUMP_REG(HDMI_NV_PDISP_SOR_STATE2); | ||
905 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AN_MSB); | ||
906 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AN_LSB); | ||
907 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CN_MSB); | ||
908 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CN_LSB); | ||
909 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AKSV_MSB); | ||
910 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AKSV_LSB); | ||
911 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_BKSV_MSB); | ||
912 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_BKSV_LSB); | ||
913 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CKSV_MSB); | ||
914 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CKSV_LSB); | ||
915 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_DKSV_MSB); | ||
916 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_DKSV_LSB); | ||
917 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CTRL); | ||
918 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CMODE); | ||
919 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB); | ||
920 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB); | ||
921 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB); | ||
922 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2); | ||
923 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1); | ||
924 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_RI); | ||
925 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CS_MSB); | ||
926 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CS_LSB); | ||
927 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU0); | ||
928 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU_RDATA0); | ||
929 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU1); | ||
930 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU2); | ||
931 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
932 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS); | ||
933 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER); | ||
934 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW); | ||
935 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH); | ||
936 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
937 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS); | ||
938 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER); | ||
939 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW); | ||
940 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH); | ||
941 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW); | ||
942 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH); | ||
943 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
944 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_STATUS); | ||
945 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_HEADER); | ||
946 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW); | ||
947 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH); | ||
948 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW); | ||
949 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH); | ||
950 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW); | ||
951 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH); | ||
952 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW); | ||
953 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH); | ||
954 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_CTRL); | ||
955 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW); | ||
956 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH); | ||
957 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); | ||
958 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); | ||
959 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW); | ||
960 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH); | ||
961 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW); | ||
962 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH); | ||
963 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW); | ||
964 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH); | ||
965 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW); | ||
966 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH); | ||
967 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW); | ||
968 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH); | ||
969 | DUMP_REG(HDMI_NV_PDISP_HDMI_CTRL); | ||
970 | DUMP_REG(HDMI_NV_PDISP_HDMI_VSYNC_KEEPOUT); | ||
971 | DUMP_REG(HDMI_NV_PDISP_HDMI_VSYNC_WINDOW); | ||
972 | DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_CTRL); | ||
973 | DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_STATUS); | ||
974 | DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_SUBPACK); | ||
975 | DUMP_REG(HDMI_NV_PDISP_HDMI_CHANNEL_STATUS1); | ||
976 | DUMP_REG(HDMI_NV_PDISP_HDMI_CHANNEL_STATUS2); | ||
977 | DUMP_REG(HDMI_NV_PDISP_HDMI_EMU0); | ||
978 | DUMP_REG(HDMI_NV_PDISP_HDMI_EMU1); | ||
979 | DUMP_REG(HDMI_NV_PDISP_HDMI_EMU1_RDATA); | ||
980 | DUMP_REG(HDMI_NV_PDISP_HDMI_SPARE); | ||
981 | DUMP_REG(HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS1); | ||
982 | DUMP_REG(HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS2); | ||
983 | DUMP_REG(HDMI_NV_PDISP_HDMI_HDCPRIF_ROM_CTRL); | ||
984 | DUMP_REG(HDMI_NV_PDISP_SOR_CAP); | ||
985 | DUMP_REG(HDMI_NV_PDISP_SOR_PWR); | ||
986 | DUMP_REG(HDMI_NV_PDISP_SOR_TEST); | ||
987 | DUMP_REG(HDMI_NV_PDISP_SOR_PLL0); | ||
988 | DUMP_REG(HDMI_NV_PDISP_SOR_PLL1); | ||
989 | DUMP_REG(HDMI_NV_PDISP_SOR_PLL2); | ||
990 | DUMP_REG(HDMI_NV_PDISP_SOR_CSTM); | ||
991 | DUMP_REG(HDMI_NV_PDISP_SOR_LVDS); | ||
992 | DUMP_REG(HDMI_NV_PDISP_SOR_CRCA); | ||
993 | DUMP_REG(HDMI_NV_PDISP_SOR_CRCB); | ||
994 | DUMP_REG(HDMI_NV_PDISP_SOR_BLANK); | ||
995 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_CTL); | ||
996 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(0)); | ||
997 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(1)); | ||
998 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(2)); | ||
999 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(3)); | ||
1000 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(4)); | ||
1001 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(5)); | ||
1002 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(6)); | ||
1003 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(7)); | ||
1004 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(8)); | ||
1005 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(9)); | ||
1006 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(10)); | ||
1007 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(11)); | ||
1008 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(12)); | ||
1009 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(13)); | ||
1010 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(14)); | ||
1011 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(15)); | ||
1012 | DUMP_REG(HDMI_NV_PDISP_SOR_VCRCA0); | ||
1013 | DUMP_REG(HDMI_NV_PDISP_SOR_VCRCA1); | ||
1014 | DUMP_REG(HDMI_NV_PDISP_SOR_CCRCA0); | ||
1015 | DUMP_REG(HDMI_NV_PDISP_SOR_CCRCA1); | ||
1016 | DUMP_REG(HDMI_NV_PDISP_SOR_EDATAA0); | ||
1017 | DUMP_REG(HDMI_NV_PDISP_SOR_EDATAA1); | ||
1018 | DUMP_REG(HDMI_NV_PDISP_SOR_COUNTA0); | ||
1019 | DUMP_REG(HDMI_NV_PDISP_SOR_COUNTA1); | ||
1020 | DUMP_REG(HDMI_NV_PDISP_SOR_DEBUGA0); | ||
1021 | DUMP_REG(HDMI_NV_PDISP_SOR_DEBUGA1); | ||
1022 | DUMP_REG(HDMI_NV_PDISP_SOR_TRIG); | ||
1023 | DUMP_REG(HDMI_NV_PDISP_SOR_MSCHECK); | ||
1024 | DUMP_REG(HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT); | ||
1025 | DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG0); | ||
1026 | DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG1); | ||
1027 | DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG2); | ||
1028 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(0)); | ||
1029 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(1)); | ||
1030 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(2)); | ||
1031 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(3)); | ||
1032 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(4)); | ||
1033 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(5)); | ||
1034 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(6)); | ||
1035 | DUMP_REG(HDMI_NV_PDISP_AUDIO_PULSE_WIDTH); | ||
1036 | DUMP_REG(HDMI_NV_PDISP_AUDIO_THRESHOLD); | ||
1037 | DUMP_REG(HDMI_NV_PDISP_AUDIO_CNTRL0); | ||
1038 | DUMP_REG(HDMI_NV_PDISP_AUDIO_N); | ||
1039 | DUMP_REG(HDMI_NV_PDISP_HDCPRIF_ROM_TIMING); | ||
1040 | DUMP_REG(HDMI_NV_PDISP_SOR_REFCLK); | ||
1041 | DUMP_REG(HDMI_NV_PDISP_CRC_CONTROL); | ||
1042 | DUMP_REG(HDMI_NV_PDISP_INPUT_CONTROL); | ||
1043 | DUMP_REG(HDMI_NV_PDISP_SCRATCH); | ||
1044 | DUMP_REG(HDMI_NV_PDISP_PE_CURRENT); | ||
1045 | DUMP_REG(HDMI_NV_PDISP_KEY_CTRL); | ||
1046 | DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG0); | ||
1047 | DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG1); | ||
1048 | DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG2); | ||
1049 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_0); | ||
1050 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_1); | ||
1051 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_2); | ||
1052 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_3); | ||
1053 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG); | ||
1054 | DUMP_REG(HDMI_NV_PDISP_KEY_SKEY_INDEX); | ||
1055 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_CNTRL0); | ||
1056 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR); | ||
1057 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE); | ||
1058 | |||
1059 | #undef DUMP_REG | ||
1060 | |||
1061 | clk_disable(hdmi->clk); | ||
1062 | |||
1063 | return 0; | ||
1064 | } | ||
1065 | |||
1066 | static struct drm_info_list debugfs_files[] = { | ||
1067 | { "regs", tegra_hdmi_show_regs, 0, NULL }, | ||
1068 | }; | ||
1069 | |||
1070 | static int tegra_hdmi_debugfs_init(struct tegra_hdmi *hdmi, | ||
1071 | struct drm_minor *minor) | ||
1072 | { | ||
1073 | unsigned int i; | ||
1074 | int err; | ||
1075 | |||
1076 | hdmi->debugfs = debugfs_create_dir("hdmi", minor->debugfs_root); | ||
1077 | if (!hdmi->debugfs) | ||
1078 | return -ENOMEM; | ||
1079 | |||
1080 | hdmi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), | ||
1081 | GFP_KERNEL); | ||
1082 | if (!hdmi->debugfs_files) { | ||
1083 | err = -ENOMEM; | ||
1084 | goto remove; | ||
1085 | } | ||
1086 | |||
1087 | for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) | ||
1088 | hdmi->debugfs_files[i].data = hdmi; | ||
1089 | |||
1090 | err = drm_debugfs_create_files(hdmi->debugfs_files, | ||
1091 | ARRAY_SIZE(debugfs_files), | ||
1092 | hdmi->debugfs, minor); | ||
1093 | if (err < 0) | ||
1094 | goto free; | ||
1095 | |||
1096 | hdmi->minor = minor; | ||
1097 | |||
1098 | return 0; | ||
1099 | |||
1100 | free: | ||
1101 | kfree(hdmi->debugfs_files); | ||
1102 | hdmi->debugfs_files = NULL; | ||
1103 | remove: | ||
1104 | debugfs_remove(hdmi->debugfs); | ||
1105 | hdmi->debugfs = NULL; | ||
1106 | |||
1107 | return err; | ||
1108 | } | ||
1109 | |||
1110 | static int tegra_hdmi_debugfs_exit(struct tegra_hdmi *hdmi) | ||
1111 | { | ||
1112 | drm_debugfs_remove_files(hdmi->debugfs_files, ARRAY_SIZE(debugfs_files), | ||
1113 | hdmi->minor); | ||
1114 | hdmi->minor = NULL; | ||
1115 | |||
1116 | kfree(hdmi->debugfs_files); | ||
1117 | hdmi->debugfs_files = NULL; | ||
1118 | |||
1119 | debugfs_remove(hdmi->debugfs); | ||
1120 | hdmi->debugfs = NULL; | ||
1121 | |||
1122 | return 0; | ||
1123 | } | ||
1124 | |||
1125 | static int tegra_hdmi_drm_init(struct host1x_client *client, | ||
1126 | struct drm_device *drm) | ||
1127 | { | ||
1128 | struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); | ||
1129 | int err; | ||
1130 | |||
1131 | hdmi->output.type = TEGRA_OUTPUT_HDMI; | ||
1132 | hdmi->output.dev = client->dev; | ||
1133 | hdmi->output.ops = &hdmi_ops; | ||
1134 | |||
1135 | err = tegra_output_init(drm, &hdmi->output); | ||
1136 | if (err < 0) { | ||
1137 | dev_err(client->dev, "output setup failed: %d\n", err); | ||
1138 | return err; | ||
1139 | } | ||
1140 | |||
1141 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
1142 | err = tegra_hdmi_debugfs_init(hdmi, drm->primary); | ||
1143 | if (err < 0) | ||
1144 | dev_err(client->dev, "debugfs setup failed: %d\n", err); | ||
1145 | } | ||
1146 | |||
1147 | return 0; | ||
1148 | } | ||
1149 | |||
1150 | static int tegra_hdmi_drm_exit(struct host1x_client *client) | ||
1151 | { | ||
1152 | struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); | ||
1153 | int err; | ||
1154 | |||
1155 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
1156 | err = tegra_hdmi_debugfs_exit(hdmi); | ||
1157 | if (err < 0) | ||
1158 | dev_err(client->dev, "debugfs cleanup failed: %d\n", | ||
1159 | err); | ||
1160 | } | ||
1161 | |||
1162 | err = tegra_output_disable(&hdmi->output); | ||
1163 | if (err < 0) { | ||
1164 | dev_err(client->dev, "output failed to disable: %d\n", err); | ||
1165 | return err; | ||
1166 | } | ||
1167 | |||
1168 | err = tegra_output_exit(&hdmi->output); | ||
1169 | if (err < 0) { | ||
1170 | dev_err(client->dev, "output cleanup failed: %d\n", err); | ||
1171 | return err; | ||
1172 | } | ||
1173 | |||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | static const struct host1x_client_ops hdmi_client_ops = { | ||
1178 | .drm_init = tegra_hdmi_drm_init, | ||
1179 | .drm_exit = tegra_hdmi_drm_exit, | ||
1180 | }; | ||
1181 | |||
1182 | static int tegra_hdmi_probe(struct platform_device *pdev) | ||
1183 | { | ||
1184 | struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent); | ||
1185 | struct tegra_hdmi *hdmi; | ||
1186 | struct resource *regs; | ||
1187 | int err; | ||
1188 | |||
1189 | hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); | ||
1190 | if (!hdmi) | ||
1191 | return -ENOMEM; | ||
1192 | |||
1193 | hdmi->dev = &pdev->dev; | ||
1194 | hdmi->audio_source = AUTO; | ||
1195 | hdmi->audio_freq = 44100; | ||
1196 | hdmi->stereo = false; | ||
1197 | hdmi->dvi = false; | ||
1198 | |||
1199 | hdmi->clk = devm_clk_get(&pdev->dev, NULL); | ||
1200 | if (IS_ERR(hdmi->clk)) { | ||
1201 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
1202 | return PTR_ERR(hdmi->clk); | ||
1203 | } | ||
1204 | |||
1205 | err = clk_prepare(hdmi->clk); | ||
1206 | if (err < 0) | ||
1207 | return err; | ||
1208 | |||
1209 | hdmi->clk_parent = devm_clk_get(&pdev->dev, "parent"); | ||
1210 | if (IS_ERR(hdmi->clk_parent)) | ||
1211 | return PTR_ERR(hdmi->clk_parent); | ||
1212 | |||
1213 | err = clk_prepare(hdmi->clk_parent); | ||
1214 | if (err < 0) | ||
1215 | return err; | ||
1216 | |||
1217 | err = clk_set_parent(hdmi->clk, hdmi->clk_parent); | ||
1218 | if (err < 0) { | ||
1219 | dev_err(&pdev->dev, "failed to setup clocks: %d\n", err); | ||
1220 | return err; | ||
1221 | } | ||
1222 | |||
1223 | hdmi->vdd = devm_regulator_get(&pdev->dev, "vdd"); | ||
1224 | if (IS_ERR(hdmi->vdd)) { | ||
1225 | dev_err(&pdev->dev, "failed to get VDD regulator\n"); | ||
1226 | return PTR_ERR(hdmi->vdd); | ||
1227 | } | ||
1228 | |||
1229 | hdmi->pll = devm_regulator_get(&pdev->dev, "pll"); | ||
1230 | if (IS_ERR(hdmi->pll)) { | ||
1231 | dev_err(&pdev->dev, "failed to get PLL regulator\n"); | ||
1232 | return PTR_ERR(hdmi->pll); | ||
1233 | } | ||
1234 | |||
1235 | hdmi->output.dev = &pdev->dev; | ||
1236 | |||
1237 | err = tegra_output_parse_dt(&hdmi->output); | ||
1238 | if (err < 0) | ||
1239 | return err; | ||
1240 | |||
1241 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1242 | if (!regs) | ||
1243 | return -ENXIO; | ||
1244 | |||
1245 | hdmi->regs = devm_ioremap_resource(&pdev->dev, regs); | ||
1246 | if (IS_ERR(hdmi->regs)) | ||
1247 | return PTR_ERR(hdmi->regs); | ||
1248 | |||
1249 | err = platform_get_irq(pdev, 0); | ||
1250 | if (err < 0) | ||
1251 | return err; | ||
1252 | |||
1253 | hdmi->irq = err; | ||
1254 | |||
1255 | hdmi->client.ops = &hdmi_client_ops; | ||
1256 | INIT_LIST_HEAD(&hdmi->client.list); | ||
1257 | hdmi->client.dev = &pdev->dev; | ||
1258 | |||
1259 | err = host1x_register_client(host1x, &hdmi->client); | ||
1260 | if (err < 0) { | ||
1261 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", | ||
1262 | err); | ||
1263 | return err; | ||
1264 | } | ||
1265 | |||
1266 | platform_set_drvdata(pdev, hdmi); | ||
1267 | |||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | static int tegra_hdmi_remove(struct platform_device *pdev) | ||
1272 | { | ||
1273 | struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent); | ||
1274 | struct tegra_hdmi *hdmi = platform_get_drvdata(pdev); | ||
1275 | int err; | ||
1276 | |||
1277 | err = host1x_unregister_client(host1x, &hdmi->client); | ||
1278 | if (err < 0) { | ||
1279 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", | ||
1280 | err); | ||
1281 | return err; | ||
1282 | } | ||
1283 | |||
1284 | clk_unprepare(hdmi->clk_parent); | ||
1285 | clk_unprepare(hdmi->clk); | ||
1286 | |||
1287 | return 0; | ||
1288 | } | ||
1289 | |||
1290 | static struct of_device_id tegra_hdmi_of_match[] = { | ||
1291 | { .compatible = "nvidia,tegra30-hdmi", }, | ||
1292 | { .compatible = "nvidia,tegra20-hdmi", }, | ||
1293 | { }, | ||
1294 | }; | ||
1295 | |||
1296 | struct platform_driver tegra_hdmi_driver = { | ||
1297 | .driver = { | ||
1298 | .name = "tegra-hdmi", | ||
1299 | .owner = THIS_MODULE, | ||
1300 | .of_match_table = tegra_hdmi_of_match, | ||
1301 | }, | ||
1302 | .probe = tegra_hdmi_probe, | ||
1303 | .remove = tegra_hdmi_remove, | ||
1304 | }; | ||
diff --git a/drivers/gpu/host1x/drm/hdmi.h b/drivers/gpu/host1x/drm/hdmi.h deleted file mode 100644 index 52ac36e08ccb..000000000000 --- a/drivers/gpu/host1x/drm/hdmi.h +++ /dev/null | |||
@@ -1,386 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Avionic Design GmbH | ||
3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #ifndef TEGRA_HDMI_H | ||
11 | #define TEGRA_HDMI_H 1 | ||
12 | |||
13 | /* register definitions */ | ||
14 | #define HDMI_CTXSW 0x00 | ||
15 | |||
16 | #define HDMI_NV_PDISP_SOR_STATE0 0x01 | ||
17 | #define SOR_STATE_UPDATE (1 << 0) | ||
18 | |||
19 | #define HDMI_NV_PDISP_SOR_STATE1 0x02 | ||
20 | #define SOR_STATE_ASY_HEAD_OPMODE_AWAKE (2 << 0) | ||
21 | #define SOR_STATE_ASY_ORMODE_NORMAL (1 << 2) | ||
22 | #define SOR_STATE_ATTACHED (1 << 3) | ||
23 | |||
24 | #define HDMI_NV_PDISP_SOR_STATE2 0x03 | ||
25 | #define SOR_STATE_ASY_OWNER_NONE (0 << 0) | ||
26 | #define SOR_STATE_ASY_OWNER_HEAD0 (1 << 0) | ||
27 | #define SOR_STATE_ASY_SUBOWNER_NONE (0 << 4) | ||
28 | #define SOR_STATE_ASY_SUBOWNER_SUBHEAD0 (1 << 4) | ||
29 | #define SOR_STATE_ASY_SUBOWNER_SUBHEAD1 (2 << 4) | ||
30 | #define SOR_STATE_ASY_SUBOWNER_BOTH (3 << 4) | ||
31 | #define SOR_STATE_ASY_CRCMODE_ACTIVE (0 << 6) | ||
32 | #define SOR_STATE_ASY_CRCMODE_COMPLETE (1 << 6) | ||
33 | #define SOR_STATE_ASY_CRCMODE_NON_ACTIVE (2 << 6) | ||
34 | #define SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A (1 << 8) | ||
35 | #define SOR_STATE_ASY_PROTOCOL_CUSTOM (15 << 8) | ||
36 | #define SOR_STATE_ASY_HSYNCPOL_POS (0 << 12) | ||
37 | #define SOR_STATE_ASY_HSYNCPOL_NEG (1 << 12) | ||
38 | #define SOR_STATE_ASY_VSYNCPOL_POS (0 << 13) | ||
39 | #define SOR_STATE_ASY_VSYNCPOL_NEG (1 << 13) | ||
40 | #define SOR_STATE_ASY_DEPOL_POS (0 << 14) | ||
41 | #define SOR_STATE_ASY_DEPOL_NEG (1 << 14) | ||
42 | |||
43 | #define HDMI_NV_PDISP_RG_HDCP_AN_MSB 0x04 | ||
44 | #define HDMI_NV_PDISP_RG_HDCP_AN_LSB 0x05 | ||
45 | #define HDMI_NV_PDISP_RG_HDCP_CN_MSB 0x06 | ||
46 | #define HDMI_NV_PDISP_RG_HDCP_CN_LSB 0x07 | ||
47 | #define HDMI_NV_PDISP_RG_HDCP_AKSV_MSB 0x08 | ||
48 | #define HDMI_NV_PDISP_RG_HDCP_AKSV_LSB 0x09 | ||
49 | #define HDMI_NV_PDISP_RG_HDCP_BKSV_MSB 0x0a | ||
50 | #define HDMI_NV_PDISP_RG_HDCP_BKSV_LSB 0x0b | ||
51 | #define HDMI_NV_PDISP_RG_HDCP_CKSV_MSB 0x0c | ||
52 | #define HDMI_NV_PDISP_RG_HDCP_CKSV_LSB 0x0d | ||
53 | #define HDMI_NV_PDISP_RG_HDCP_DKSV_MSB 0x0e | ||
54 | #define HDMI_NV_PDISP_RG_HDCP_DKSV_LSB 0x0f | ||
55 | #define HDMI_NV_PDISP_RG_HDCP_CTRL 0x10 | ||
56 | #define HDMI_NV_PDISP_RG_HDCP_CMODE 0x11 | ||
57 | #define HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB 0x12 | ||
58 | #define HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB 0x13 | ||
59 | #define HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB 0x14 | ||
60 | #define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2 0x15 | ||
61 | #define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1 0x16 | ||
62 | #define HDMI_NV_PDISP_RG_HDCP_RI 0x17 | ||
63 | #define HDMI_NV_PDISP_RG_HDCP_CS_MSB 0x18 | ||
64 | #define HDMI_NV_PDISP_RG_HDCP_CS_LSB 0x19 | ||
65 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU0 0x1a | ||
66 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU_RDATA0 0x1b | ||
67 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU1 0x1c | ||
68 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU2 0x1d | ||
69 | |||
70 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL 0x1e | ||
71 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS 0x1f | ||
72 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER 0x20 | ||
73 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW 0x21 | ||
74 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH 0x22 | ||
75 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL 0x23 | ||
76 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS 0x24 | ||
77 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER 0x25 | ||
78 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW 0x26 | ||
79 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH 0x27 | ||
80 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW 0x28 | ||
81 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH 0x29 | ||
82 | |||
83 | #define INFOFRAME_CTRL_ENABLE (1 << 0) | ||
84 | |||
85 | #define INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0) | ||
86 | #define INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8) | ||
87 | #define INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16) | ||
88 | |||
89 | #define HDMI_NV_PDISP_HDMI_GENERIC_CTRL 0x2a | ||
90 | #define GENERIC_CTRL_ENABLE (1 << 0) | ||
91 | #define GENERIC_CTRL_OTHER (1 << 4) | ||
92 | #define GENERIC_CTRL_SINGLE (1 << 8) | ||
93 | #define GENERIC_CTRL_HBLANK (1 << 12) | ||
94 | #define GENERIC_CTRL_AUDIO (1 << 16) | ||
95 | |||
96 | #define HDMI_NV_PDISP_HDMI_GENERIC_STATUS 0x2b | ||
97 | #define HDMI_NV_PDISP_HDMI_GENERIC_HEADER 0x2c | ||
98 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW 0x2d | ||
99 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH 0x2e | ||
100 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW 0x2f | ||
101 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH 0x30 | ||
102 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW 0x31 | ||
103 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH 0x32 | ||
104 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW 0x33 | ||
105 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH 0x34 | ||
106 | |||
107 | #define HDMI_NV_PDISP_HDMI_ACR_CTRL 0x35 | ||
108 | #define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW 0x36 | ||
109 | #define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH 0x37 | ||
110 | #define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW 0x38 | ||
111 | #define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH 0x39 | ||
112 | #define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW 0x3a | ||
113 | #define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH 0x3b | ||
114 | #define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW 0x3c | ||
115 | #define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH 0x3d | ||
116 | #define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW 0x3e | ||
117 | #define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH 0x3f | ||
118 | #define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW 0x40 | ||
119 | #define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH 0x41 | ||
120 | #define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW 0x42 | ||
121 | #define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH 0x43 | ||
122 | |||
123 | #define ACR_SUBPACK_CTS(x) (((x) & 0xffffff) << 8) | ||
124 | #define ACR_SUBPACK_N(x) (((x) & 0xffffff) << 0) | ||
125 | #define ACR_ENABLE (1 << 31) | ||
126 | |||
127 | #define HDMI_NV_PDISP_HDMI_CTRL 0x44 | ||
128 | #define HDMI_CTRL_REKEY(x) (((x) & 0x7f) << 0) | ||
129 | #define HDMI_CTRL_MAX_AC_PACKET(x) (((x) & 0x1f) << 16) | ||
130 | #define HDMI_CTRL_ENABLE (1 << 30) | ||
131 | |||
132 | #define HDMI_NV_PDISP_HDMI_VSYNC_KEEPOUT 0x45 | ||
133 | #define HDMI_NV_PDISP_HDMI_VSYNC_WINDOW 0x46 | ||
134 | #define VSYNC_WINDOW_END(x) (((x) & 0x3ff) << 0) | ||
135 | #define VSYNC_WINDOW_START(x) (((x) & 0x3ff) << 16) | ||
136 | #define VSYNC_WINDOW_ENABLE (1 << 31) | ||
137 | |||
138 | #define HDMI_NV_PDISP_HDMI_GCP_CTRL 0x47 | ||
139 | #define HDMI_NV_PDISP_HDMI_GCP_STATUS 0x48 | ||
140 | #define HDMI_NV_PDISP_HDMI_GCP_SUBPACK 0x49 | ||
141 | #define HDMI_NV_PDISP_HDMI_CHANNEL_STATUS1 0x4a | ||
142 | #define HDMI_NV_PDISP_HDMI_CHANNEL_STATUS2 0x4b | ||
143 | #define HDMI_NV_PDISP_HDMI_EMU0 0x4c | ||
144 | #define HDMI_NV_PDISP_HDMI_EMU1 0x4d | ||
145 | #define HDMI_NV_PDISP_HDMI_EMU1_RDATA 0x4e | ||
146 | |||
147 | #define HDMI_NV_PDISP_HDMI_SPARE 0x4f | ||
148 | #define SPARE_HW_CTS (1 << 0) | ||
149 | #define SPARE_FORCE_SW_CTS (1 << 1) | ||
150 | #define SPARE_CTS_RESET_VAL(x) (((x) & 0x7) << 16) | ||
151 | |||
152 | #define HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS1 0x50 | ||
153 | #define HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS2 0x51 | ||
154 | #define HDMI_NV_PDISP_HDMI_HDCPRIF_ROM_CTRL 0x53 | ||
155 | #define HDMI_NV_PDISP_SOR_CAP 0x54 | ||
156 | #define HDMI_NV_PDISP_SOR_PWR 0x55 | ||
157 | #define SOR_PWR_NORMAL_STATE_PD (0 << 0) | ||
158 | #define SOR_PWR_NORMAL_STATE_PU (1 << 0) | ||
159 | #define SOR_PWR_NORMAL_START_NORMAL (0 << 1) | ||
160 | #define SOR_PWR_NORMAL_START_ALT (1 << 1) | ||
161 | #define SOR_PWR_SAFE_STATE_PD (0 << 16) | ||
162 | #define SOR_PWR_SAFE_STATE_PU (1 << 16) | ||
163 | #define SOR_PWR_SETTING_NEW_DONE (0 << 31) | ||
164 | #define SOR_PWR_SETTING_NEW_PENDING (1 << 31) | ||
165 | #define SOR_PWR_SETTING_NEW_TRIGGER (1 << 31) | ||
166 | |||
167 | #define HDMI_NV_PDISP_SOR_TEST 0x56 | ||
168 | #define HDMI_NV_PDISP_SOR_PLL0 0x57 | ||
169 | #define SOR_PLL_PWR (1 << 0) | ||
170 | #define SOR_PLL_PDBG (1 << 1) | ||
171 | #define SOR_PLL_VCAPD (1 << 2) | ||
172 | #define SOR_PLL_PDPORT (1 << 3) | ||
173 | #define SOR_PLL_RESISTORSEL (1 << 4) | ||
174 | #define SOR_PLL_PULLDOWN (1 << 5) | ||
175 | #define SOR_PLL_VCOCAP(x) (((x) & 0xf) << 8) | ||
176 | #define SOR_PLL_BG_V17_S(x) (((x) & 0xf) << 12) | ||
177 | #define SOR_PLL_FILTER(x) (((x) & 0xf) << 16) | ||
178 | #define SOR_PLL_ICHPMP(x) (((x) & 0xf) << 24) | ||
179 | #define SOR_PLL_TX_REG_LOAD(x) (((x) & 0xf) << 28) | ||
180 | |||
181 | #define HDMI_NV_PDISP_SOR_PLL1 0x58 | ||
182 | #define SOR_PLL_TMDS_TERM_ENABLE (1 << 8) | ||
183 | #define SOR_PLL_TMDS_TERMADJ(x) (((x) & 0xf) << 9) | ||
184 | #define SOR_PLL_LOADADJ(x) (((x) & 0xf) << 20) | ||
185 | #define SOR_PLL_PE_EN (1 << 28) | ||
186 | #define SOR_PLL_HALF_FULL_PE (1 << 29) | ||
187 | #define SOR_PLL_S_D_PIN_PE (1 << 30) | ||
188 | |||
189 | #define HDMI_NV_PDISP_SOR_PLL2 0x59 | ||
190 | |||
191 | #define HDMI_NV_PDISP_SOR_CSTM 0x5a | ||
192 | #define SOR_CSTM_ROTCLK(x) (((x) & 0xf) << 24) | ||
193 | |||
194 | #define HDMI_NV_PDISP_SOR_LVDS 0x5b | ||
195 | #define HDMI_NV_PDISP_SOR_CRCA 0x5c | ||
196 | #define HDMI_NV_PDISP_SOR_CRCB 0x5d | ||
197 | #define HDMI_NV_PDISP_SOR_BLANK 0x5e | ||
198 | #define HDMI_NV_PDISP_SOR_SEQ_CTL 0x5f | ||
199 | #define SOR_SEQ_CTL_PU_PC(x) (((x) & 0xf) << 0) | ||
200 | #define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) << 4) | ||
201 | #define SOR_SEQ_PD_PC(x) (((x) & 0xf) << 8) | ||
202 | #define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12) | ||
203 | #define SOR_SEQ_PC(x) (((x) & 0xf) << 16) | ||
204 | #define SOR_SEQ_STATUS (1 << 28) | ||
205 | #define SOR_SEQ_SWITCH (1 << 30) | ||
206 | |||
207 | #define HDMI_NV_PDISP_SOR_SEQ_INST(x) (0x60 + (x)) | ||
208 | |||
209 | #define SOR_SEQ_INST_WAIT_TIME(x) (((x) & 0x3ff) << 0) | ||
210 | #define SOR_SEQ_INST_WAIT_UNITS_VSYNC (2 << 12) | ||
211 | #define SOR_SEQ_INST_HALT (1 << 15) | ||
212 | #define SOR_SEQ_INST_PIN_A_LOW (0 << 21) | ||
213 | #define SOR_SEQ_INST_PIN_A_HIGH (1 << 21) | ||
214 | #define SOR_SEQ_INST_PIN_B_LOW (0 << 22) | ||
215 | #define SOR_SEQ_INST_PIN_B_HIGH (1 << 22) | ||
216 | #define SOR_SEQ_INST_DRIVE_PWM_OUT_LO (1 << 23) | ||
217 | |||
218 | #define HDMI_NV_PDISP_SOR_VCRCA0 0x72 | ||
219 | #define HDMI_NV_PDISP_SOR_VCRCA1 0x73 | ||
220 | #define HDMI_NV_PDISP_SOR_CCRCA0 0x74 | ||
221 | #define HDMI_NV_PDISP_SOR_CCRCA1 0x75 | ||
222 | #define HDMI_NV_PDISP_SOR_EDATAA0 0x76 | ||
223 | #define HDMI_NV_PDISP_SOR_EDATAA1 0x77 | ||
224 | #define HDMI_NV_PDISP_SOR_COUNTA0 0x78 | ||
225 | #define HDMI_NV_PDISP_SOR_COUNTA1 0x79 | ||
226 | #define HDMI_NV_PDISP_SOR_DEBUGA0 0x7a | ||
227 | #define HDMI_NV_PDISP_SOR_DEBUGA1 0x7b | ||
228 | #define HDMI_NV_PDISP_SOR_TRIG 0x7c | ||
229 | #define HDMI_NV_PDISP_SOR_MSCHECK 0x7d | ||
230 | |||
231 | #define HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT 0x7e | ||
232 | #define DRIVE_CURRENT_LANE0(x) (((x) & 0x3f) << 0) | ||
233 | #define DRIVE_CURRENT_LANE1(x) (((x) & 0x3f) << 8) | ||
234 | #define DRIVE_CURRENT_LANE2(x) (((x) & 0x3f) << 16) | ||
235 | #define DRIVE_CURRENT_LANE3(x) (((x) & 0x3f) << 24) | ||
236 | #define DRIVE_CURRENT_FUSE_OVERRIDE (1 << 31) | ||
237 | |||
238 | #define DRIVE_CURRENT_1_500_mA 0x00 | ||
239 | #define DRIVE_CURRENT_1_875_mA 0x01 | ||
240 | #define DRIVE_CURRENT_2_250_mA 0x02 | ||
241 | #define DRIVE_CURRENT_2_625_mA 0x03 | ||
242 | #define DRIVE_CURRENT_3_000_mA 0x04 | ||
243 | #define DRIVE_CURRENT_3_375_mA 0x05 | ||
244 | #define DRIVE_CURRENT_3_750_mA 0x06 | ||
245 | #define DRIVE_CURRENT_4_125_mA 0x07 | ||
246 | #define DRIVE_CURRENT_4_500_mA 0x08 | ||
247 | #define DRIVE_CURRENT_4_875_mA 0x09 | ||
248 | #define DRIVE_CURRENT_5_250_mA 0x0a | ||
249 | #define DRIVE_CURRENT_5_625_mA 0x0b | ||
250 | #define DRIVE_CURRENT_6_000_mA 0x0c | ||
251 | #define DRIVE_CURRENT_6_375_mA 0x0d | ||
252 | #define DRIVE_CURRENT_6_750_mA 0x0e | ||
253 | #define DRIVE_CURRENT_7_125_mA 0x0f | ||
254 | #define DRIVE_CURRENT_7_500_mA 0x10 | ||
255 | #define DRIVE_CURRENT_7_875_mA 0x11 | ||
256 | #define DRIVE_CURRENT_8_250_mA 0x12 | ||
257 | #define DRIVE_CURRENT_8_625_mA 0x13 | ||
258 | #define DRIVE_CURRENT_9_000_mA 0x14 | ||
259 | #define DRIVE_CURRENT_9_375_mA 0x15 | ||
260 | #define DRIVE_CURRENT_9_750_mA 0x16 | ||
261 | #define DRIVE_CURRENT_10_125_mA 0x17 | ||
262 | #define DRIVE_CURRENT_10_500_mA 0x18 | ||
263 | #define DRIVE_CURRENT_10_875_mA 0x19 | ||
264 | #define DRIVE_CURRENT_11_250_mA 0x1a | ||
265 | #define DRIVE_CURRENT_11_625_mA 0x1b | ||
266 | #define DRIVE_CURRENT_12_000_mA 0x1c | ||
267 | #define DRIVE_CURRENT_12_375_mA 0x1d | ||
268 | #define DRIVE_CURRENT_12_750_mA 0x1e | ||
269 | #define DRIVE_CURRENT_13_125_mA 0x1f | ||
270 | #define DRIVE_CURRENT_13_500_mA 0x20 | ||
271 | #define DRIVE_CURRENT_13_875_mA 0x21 | ||
272 | #define DRIVE_CURRENT_14_250_mA 0x22 | ||
273 | #define DRIVE_CURRENT_14_625_mA 0x23 | ||
274 | #define DRIVE_CURRENT_15_000_mA 0x24 | ||
275 | #define DRIVE_CURRENT_15_375_mA 0x25 | ||
276 | #define DRIVE_CURRENT_15_750_mA 0x26 | ||
277 | #define DRIVE_CURRENT_16_125_mA 0x27 | ||
278 | #define DRIVE_CURRENT_16_500_mA 0x28 | ||
279 | #define DRIVE_CURRENT_16_875_mA 0x29 | ||
280 | #define DRIVE_CURRENT_17_250_mA 0x2a | ||
281 | #define DRIVE_CURRENT_17_625_mA 0x2b | ||
282 | #define DRIVE_CURRENT_18_000_mA 0x2c | ||
283 | #define DRIVE_CURRENT_18_375_mA 0x2d | ||
284 | #define DRIVE_CURRENT_18_750_mA 0x2e | ||
285 | #define DRIVE_CURRENT_19_125_mA 0x2f | ||
286 | #define DRIVE_CURRENT_19_500_mA 0x30 | ||
287 | #define DRIVE_CURRENT_19_875_mA 0x31 | ||
288 | #define DRIVE_CURRENT_20_250_mA 0x32 | ||
289 | #define DRIVE_CURRENT_20_625_mA 0x33 | ||
290 | #define DRIVE_CURRENT_21_000_mA 0x34 | ||
291 | #define DRIVE_CURRENT_21_375_mA 0x35 | ||
292 | #define DRIVE_CURRENT_21_750_mA 0x36 | ||
293 | #define DRIVE_CURRENT_22_125_mA 0x37 | ||
294 | #define DRIVE_CURRENT_22_500_mA 0x38 | ||
295 | #define DRIVE_CURRENT_22_875_mA 0x39 | ||
296 | #define DRIVE_CURRENT_23_250_mA 0x3a | ||
297 | #define DRIVE_CURRENT_23_625_mA 0x3b | ||
298 | #define DRIVE_CURRENT_24_000_mA 0x3c | ||
299 | #define DRIVE_CURRENT_24_375_mA 0x3d | ||
300 | #define DRIVE_CURRENT_24_750_mA 0x3e | ||
301 | |||
302 | #define HDMI_NV_PDISP_AUDIO_DEBUG0 0x7f | ||
303 | #define HDMI_NV_PDISP_AUDIO_DEBUG1 0x80 | ||
304 | #define HDMI_NV_PDISP_AUDIO_DEBUG2 0x81 | ||
305 | |||
306 | #define HDMI_NV_PDISP_AUDIO_FS(x) (0x82 + (x)) | ||
307 | #define AUDIO_FS_LOW(x) (((x) & 0xfff) << 0) | ||
308 | #define AUDIO_FS_HIGH(x) (((x) & 0xfff) << 16) | ||
309 | |||
310 | #define HDMI_NV_PDISP_AUDIO_PULSE_WIDTH 0x89 | ||
311 | #define HDMI_NV_PDISP_AUDIO_THRESHOLD 0x8a | ||
312 | #define HDMI_NV_PDISP_AUDIO_CNTRL0 0x8b | ||
313 | #define AUDIO_CNTRL0_ERROR_TOLERANCE(x) (((x) & 0xff) << 0) | ||
314 | #define AUDIO_CNTRL0_SOURCE_SELECT_AUTO (0 << 20) | ||
315 | #define AUDIO_CNTRL0_SOURCE_SELECT_SPDIF (1 << 20) | ||
316 | #define AUDIO_CNTRL0_SOURCE_SELECT_HDAL (2 << 20) | ||
317 | #define AUDIO_CNTRL0_FRAMES_PER_BLOCK(x) (((x) & 0xff) << 24) | ||
318 | |||
319 | #define HDMI_NV_PDISP_AUDIO_N 0x8c | ||
320 | #define AUDIO_N_VALUE(x) (((x) & 0xfffff) << 0) | ||
321 | #define AUDIO_N_RESETF (1 << 20) | ||
322 | #define AUDIO_N_GENERATE_NORMAL (0 << 24) | ||
323 | #define AUDIO_N_GENERATE_ALTERNATE (1 << 24) | ||
324 | |||
325 | #define HDMI_NV_PDISP_HDCPRIF_ROM_TIMING 0x94 | ||
326 | #define HDMI_NV_PDISP_SOR_REFCLK 0x95 | ||
327 | #define SOR_REFCLK_DIV_INT(x) (((x) & 0xff) << 8) | ||
328 | #define SOR_REFCLK_DIV_FRAC(x) (((x) & 0x03) << 6) | ||
329 | |||
330 | #define HDMI_NV_PDISP_CRC_CONTROL 0x96 | ||
331 | #define HDMI_NV_PDISP_INPUT_CONTROL 0x97 | ||
332 | #define HDMI_SRC_DISPLAYA (0 << 0) | ||
333 | #define HDMI_SRC_DISPLAYB (1 << 0) | ||
334 | #define ARM_VIDEO_RANGE_FULL (0 << 1) | ||
335 | #define ARM_VIDEO_RANGE_LIMITED (1 << 1) | ||
336 | |||
337 | #define HDMI_NV_PDISP_SCRATCH 0x98 | ||
338 | #define HDMI_NV_PDISP_PE_CURRENT 0x99 | ||
339 | #define PE_CURRENT0(x) (((x) & 0xf) << 0) | ||
340 | #define PE_CURRENT1(x) (((x) & 0xf) << 8) | ||
341 | #define PE_CURRENT2(x) (((x) & 0xf) << 16) | ||
342 | #define PE_CURRENT3(x) (((x) & 0xf) << 24) | ||
343 | |||
344 | #define PE_CURRENT_0_0_mA 0x0 | ||
345 | #define PE_CURRENT_0_5_mA 0x1 | ||
346 | #define PE_CURRENT_1_0_mA 0x2 | ||
347 | #define PE_CURRENT_1_5_mA 0x3 | ||
348 | #define PE_CURRENT_2_0_mA 0x4 | ||
349 | #define PE_CURRENT_2_5_mA 0x5 | ||
350 | #define PE_CURRENT_3_0_mA 0x6 | ||
351 | #define PE_CURRENT_3_5_mA 0x7 | ||
352 | #define PE_CURRENT_4_0_mA 0x8 | ||
353 | #define PE_CURRENT_4_5_mA 0x9 | ||
354 | #define PE_CURRENT_5_0_mA 0xa | ||
355 | #define PE_CURRENT_5_5_mA 0xb | ||
356 | #define PE_CURRENT_6_0_mA 0xc | ||
357 | #define PE_CURRENT_6_5_mA 0xd | ||
358 | #define PE_CURRENT_7_0_mA 0xe | ||
359 | #define PE_CURRENT_7_5_mA 0xf | ||
360 | |||
361 | #define HDMI_NV_PDISP_KEY_CTRL 0x9a | ||
362 | #define HDMI_NV_PDISP_KEY_DEBUG0 0x9b | ||
363 | #define HDMI_NV_PDISP_KEY_DEBUG1 0x9c | ||
364 | #define HDMI_NV_PDISP_KEY_DEBUG2 0x9d | ||
365 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_0 0x9e | ||
366 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_1 0x9f | ||
367 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_2 0xa0 | ||
368 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_3 0xa1 | ||
369 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG 0xa2 | ||
370 | #define HDMI_NV_PDISP_KEY_SKEY_INDEX 0xa3 | ||
371 | |||
372 | #define HDMI_NV_PDISP_SOR_AUDIO_CNTRL0 0xac | ||
373 | #define AUDIO_CNTRL0_INJECT_NULLSMPL (1 << 29) | ||
374 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR 0xbc | ||
375 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE 0xbd | ||
376 | |||
377 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320 0xbf | ||
378 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441 0xc0 | ||
379 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882 0xc1 | ||
380 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764 0xc2 | ||
381 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480 0xc3 | ||
382 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960 0xc4 | ||
383 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920 0xc5 | ||
384 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_DEFAULT 0xc5 | ||
385 | |||
386 | #endif /* TEGRA_HDMI_H */ | ||
diff --git a/drivers/gpu/host1x/drm/output.c b/drivers/gpu/host1x/drm/output.c deleted file mode 100644 index 137ae81ab80e..000000000000 --- a/drivers/gpu/host1x/drm/output.c +++ /dev/null | |||
@@ -1,272 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Avionic Design GmbH | ||
3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/of_gpio.h> | ||
12 | #include <linux/i2c.h> | ||
13 | |||
14 | #include "drm.h" | ||
15 | |||
16 | static int tegra_connector_get_modes(struct drm_connector *connector) | ||
17 | { | ||
18 | struct tegra_output *output = connector_to_output(connector); | ||
19 | struct edid *edid = NULL; | ||
20 | int err = 0; | ||
21 | |||
22 | if (output->edid) | ||
23 | edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL); | ||
24 | else if (output->ddc) | ||
25 | edid = drm_get_edid(connector, output->ddc); | ||
26 | |||
27 | drm_mode_connector_update_edid_property(connector, edid); | ||
28 | |||
29 | if (edid) { | ||
30 | err = drm_add_edid_modes(connector, edid); | ||
31 | kfree(edid); | ||
32 | } | ||
33 | |||
34 | return err; | ||
35 | } | ||
36 | |||
37 | static int tegra_connector_mode_valid(struct drm_connector *connector, | ||
38 | struct drm_display_mode *mode) | ||
39 | { | ||
40 | struct tegra_output *output = connector_to_output(connector); | ||
41 | enum drm_mode_status status = MODE_OK; | ||
42 | int err; | ||
43 | |||
44 | err = tegra_output_check_mode(output, mode, &status); | ||
45 | if (err < 0) | ||
46 | return MODE_ERROR; | ||
47 | |||
48 | return status; | ||
49 | } | ||
50 | |||
51 | static struct drm_encoder * | ||
52 | tegra_connector_best_encoder(struct drm_connector *connector) | ||
53 | { | ||
54 | struct tegra_output *output = connector_to_output(connector); | ||
55 | |||
56 | return &output->encoder; | ||
57 | } | ||
58 | |||
59 | static const struct drm_connector_helper_funcs connector_helper_funcs = { | ||
60 | .get_modes = tegra_connector_get_modes, | ||
61 | .mode_valid = tegra_connector_mode_valid, | ||
62 | .best_encoder = tegra_connector_best_encoder, | ||
63 | }; | ||
64 | |||
65 | static enum drm_connector_status | ||
66 | tegra_connector_detect(struct drm_connector *connector, bool force) | ||
67 | { | ||
68 | struct tegra_output *output = connector_to_output(connector); | ||
69 | enum drm_connector_status status = connector_status_unknown; | ||
70 | |||
71 | if (gpio_is_valid(output->hpd_gpio)) { | ||
72 | if (gpio_get_value(output->hpd_gpio) == 0) | ||
73 | status = connector_status_disconnected; | ||
74 | else | ||
75 | status = connector_status_connected; | ||
76 | } else { | ||
77 | if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) | ||
78 | status = connector_status_connected; | ||
79 | } | ||
80 | |||
81 | return status; | ||
82 | } | ||
83 | |||
84 | static void tegra_connector_destroy(struct drm_connector *connector) | ||
85 | { | ||
86 | drm_sysfs_connector_remove(connector); | ||
87 | drm_connector_cleanup(connector); | ||
88 | } | ||
89 | |||
90 | static const struct drm_connector_funcs connector_funcs = { | ||
91 | .dpms = drm_helper_connector_dpms, | ||
92 | .detect = tegra_connector_detect, | ||
93 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
94 | .destroy = tegra_connector_destroy, | ||
95 | }; | ||
96 | |||
97 | static void tegra_encoder_destroy(struct drm_encoder *encoder) | ||
98 | { | ||
99 | drm_encoder_cleanup(encoder); | ||
100 | } | ||
101 | |||
102 | static const struct drm_encoder_funcs encoder_funcs = { | ||
103 | .destroy = tegra_encoder_destroy, | ||
104 | }; | ||
105 | |||
106 | static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode) | ||
107 | { | ||
108 | } | ||
109 | |||
110 | static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder, | ||
111 | const struct drm_display_mode *mode, | ||
112 | struct drm_display_mode *adjusted) | ||
113 | { | ||
114 | return true; | ||
115 | } | ||
116 | |||
117 | static void tegra_encoder_prepare(struct drm_encoder *encoder) | ||
118 | { | ||
119 | } | ||
120 | |||
121 | static void tegra_encoder_commit(struct drm_encoder *encoder) | ||
122 | { | ||
123 | } | ||
124 | |||
125 | static void tegra_encoder_mode_set(struct drm_encoder *encoder, | ||
126 | struct drm_display_mode *mode, | ||
127 | struct drm_display_mode *adjusted) | ||
128 | { | ||
129 | struct tegra_output *output = encoder_to_output(encoder); | ||
130 | int err; | ||
131 | |||
132 | err = tegra_output_enable(output); | ||
133 | if (err < 0) | ||
134 | dev_err(encoder->dev->dev, "tegra_output_enable(): %d\n", err); | ||
135 | } | ||
136 | |||
137 | static const struct drm_encoder_helper_funcs encoder_helper_funcs = { | ||
138 | .dpms = tegra_encoder_dpms, | ||
139 | .mode_fixup = tegra_encoder_mode_fixup, | ||
140 | .prepare = tegra_encoder_prepare, | ||
141 | .commit = tegra_encoder_commit, | ||
142 | .mode_set = tegra_encoder_mode_set, | ||
143 | }; | ||
144 | |||
145 | static irqreturn_t hpd_irq(int irq, void *data) | ||
146 | { | ||
147 | struct tegra_output *output = data; | ||
148 | |||
149 | drm_helper_hpd_irq_event(output->connector.dev); | ||
150 | |||
151 | return IRQ_HANDLED; | ||
152 | } | ||
153 | |||
154 | int tegra_output_parse_dt(struct tegra_output *output) | ||
155 | { | ||
156 | enum of_gpio_flags flags; | ||
157 | struct device_node *ddc; | ||
158 | size_t size; | ||
159 | int err; | ||
160 | |||
161 | if (!output->of_node) | ||
162 | output->of_node = output->dev->of_node; | ||
163 | |||
164 | output->edid = of_get_property(output->of_node, "nvidia,edid", &size); | ||
165 | |||
166 | ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0); | ||
167 | if (ddc) { | ||
168 | output->ddc = of_find_i2c_adapter_by_node(ddc); | ||
169 | if (!output->ddc) { | ||
170 | err = -EPROBE_DEFER; | ||
171 | of_node_put(ddc); | ||
172 | return err; | ||
173 | } | ||
174 | |||
175 | of_node_put(ddc); | ||
176 | } | ||
177 | |||
178 | if (!output->edid && !output->ddc) | ||
179 | return -ENODEV; | ||
180 | |||
181 | output->hpd_gpio = of_get_named_gpio_flags(output->of_node, | ||
182 | "nvidia,hpd-gpio", 0, | ||
183 | &flags); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | int tegra_output_init(struct drm_device *drm, struct tegra_output *output) | ||
189 | { | ||
190 | int connector, encoder, err; | ||
191 | |||
192 | if (gpio_is_valid(output->hpd_gpio)) { | ||
193 | unsigned long flags; | ||
194 | |||
195 | err = gpio_request_one(output->hpd_gpio, GPIOF_DIR_IN, | ||
196 | "HDMI hotplug detect"); | ||
197 | if (err < 0) { | ||
198 | dev_err(output->dev, "gpio_request_one(): %d\n", err); | ||
199 | return err; | ||
200 | } | ||
201 | |||
202 | err = gpio_to_irq(output->hpd_gpio); | ||
203 | if (err < 0) { | ||
204 | dev_err(output->dev, "gpio_to_irq(): %d\n", err); | ||
205 | goto free_hpd; | ||
206 | } | ||
207 | |||
208 | output->hpd_irq = err; | ||
209 | |||
210 | flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | | ||
211 | IRQF_ONESHOT; | ||
212 | |||
213 | err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq, | ||
214 | flags, "hpd", output); | ||
215 | if (err < 0) { | ||
216 | dev_err(output->dev, "failed to request IRQ#%u: %d\n", | ||
217 | output->hpd_irq, err); | ||
218 | goto free_hpd; | ||
219 | } | ||
220 | |||
221 | output->connector.polled = DRM_CONNECTOR_POLL_HPD; | ||
222 | } | ||
223 | |||
224 | switch (output->type) { | ||
225 | case TEGRA_OUTPUT_RGB: | ||
226 | connector = DRM_MODE_CONNECTOR_LVDS; | ||
227 | encoder = DRM_MODE_ENCODER_LVDS; | ||
228 | break; | ||
229 | |||
230 | case TEGRA_OUTPUT_HDMI: | ||
231 | connector = DRM_MODE_CONNECTOR_HDMIA; | ||
232 | encoder = DRM_MODE_ENCODER_TMDS; | ||
233 | break; | ||
234 | |||
235 | default: | ||
236 | connector = DRM_MODE_CONNECTOR_Unknown; | ||
237 | encoder = DRM_MODE_ENCODER_NONE; | ||
238 | break; | ||
239 | } | ||
240 | |||
241 | drm_connector_init(drm, &output->connector, &connector_funcs, | ||
242 | connector); | ||
243 | drm_connector_helper_add(&output->connector, &connector_helper_funcs); | ||
244 | |||
245 | drm_encoder_init(drm, &output->encoder, &encoder_funcs, encoder); | ||
246 | drm_encoder_helper_add(&output->encoder, &encoder_helper_funcs); | ||
247 | |||
248 | drm_mode_connector_attach_encoder(&output->connector, &output->encoder); | ||
249 | drm_sysfs_connector_add(&output->connector); | ||
250 | |||
251 | output->encoder.possible_crtcs = 0x3; | ||
252 | |||
253 | return 0; | ||
254 | |||
255 | free_hpd: | ||
256 | gpio_free(output->hpd_gpio); | ||
257 | |||
258 | return err; | ||
259 | } | ||
260 | |||
261 | int tegra_output_exit(struct tegra_output *output) | ||
262 | { | ||
263 | if (gpio_is_valid(output->hpd_gpio)) { | ||
264 | free_irq(output->hpd_irq, output); | ||
265 | gpio_free(output->hpd_gpio); | ||
266 | } | ||
267 | |||
268 | if (output->ddc) | ||
269 | put_device(&output->ddc->dev); | ||
270 | |||
271 | return 0; | ||
272 | } | ||
diff --git a/drivers/gpu/host1x/drm/rgb.c b/drivers/gpu/host1x/drm/rgb.c deleted file mode 100644 index 5aa66ef7a946..000000000000 --- a/drivers/gpu/host1x/drm/rgb.c +++ /dev/null | |||
@@ -1,228 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Avionic Design GmbH | ||
3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/of.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | |||
15 | #include "drm.h" | ||
16 | #include "dc.h" | ||
17 | |||
18 | struct tegra_rgb { | ||
19 | struct tegra_output output; | ||
20 | struct clk *clk_parent; | ||
21 | struct clk *clk; | ||
22 | }; | ||
23 | |||
24 | static inline struct tegra_rgb *to_rgb(struct tegra_output *output) | ||
25 | { | ||
26 | return container_of(output, struct tegra_rgb, output); | ||
27 | } | ||
28 | |||
29 | struct reg_entry { | ||
30 | unsigned long offset; | ||
31 | unsigned long value; | ||
32 | }; | ||
33 | |||
34 | static const struct reg_entry rgb_enable[] = { | ||
35 | { DC_COM_PIN_OUTPUT_ENABLE(0), 0x00000000 }, | ||
36 | { DC_COM_PIN_OUTPUT_ENABLE(1), 0x00000000 }, | ||
37 | { DC_COM_PIN_OUTPUT_ENABLE(2), 0x00000000 }, | ||
38 | { DC_COM_PIN_OUTPUT_ENABLE(3), 0x00000000 }, | ||
39 | { DC_COM_PIN_OUTPUT_POLARITY(0), 0x00000000 }, | ||
40 | { DC_COM_PIN_OUTPUT_POLARITY(1), 0x01000000 }, | ||
41 | { DC_COM_PIN_OUTPUT_POLARITY(2), 0x00000000 }, | ||
42 | { DC_COM_PIN_OUTPUT_POLARITY(3), 0x00000000 }, | ||
43 | { DC_COM_PIN_OUTPUT_DATA(0), 0x00000000 }, | ||
44 | { DC_COM_PIN_OUTPUT_DATA(1), 0x00000000 }, | ||
45 | { DC_COM_PIN_OUTPUT_DATA(2), 0x00000000 }, | ||
46 | { DC_COM_PIN_OUTPUT_DATA(3), 0x00000000 }, | ||
47 | { DC_COM_PIN_OUTPUT_SELECT(0), 0x00000000 }, | ||
48 | { DC_COM_PIN_OUTPUT_SELECT(1), 0x00000000 }, | ||
49 | { DC_COM_PIN_OUTPUT_SELECT(2), 0x00000000 }, | ||
50 | { DC_COM_PIN_OUTPUT_SELECT(3), 0x00000000 }, | ||
51 | { DC_COM_PIN_OUTPUT_SELECT(4), 0x00210222 }, | ||
52 | { DC_COM_PIN_OUTPUT_SELECT(5), 0x00002200 }, | ||
53 | { DC_COM_PIN_OUTPUT_SELECT(6), 0x00020000 }, | ||
54 | }; | ||
55 | |||
56 | static const struct reg_entry rgb_disable[] = { | ||
57 | { DC_COM_PIN_OUTPUT_SELECT(6), 0x00000000 }, | ||
58 | { DC_COM_PIN_OUTPUT_SELECT(5), 0x00000000 }, | ||
59 | { DC_COM_PIN_OUTPUT_SELECT(4), 0x00000000 }, | ||
60 | { DC_COM_PIN_OUTPUT_SELECT(3), 0x00000000 }, | ||
61 | { DC_COM_PIN_OUTPUT_SELECT(2), 0x00000000 }, | ||
62 | { DC_COM_PIN_OUTPUT_SELECT(1), 0x00000000 }, | ||
63 | { DC_COM_PIN_OUTPUT_SELECT(0), 0x00000000 }, | ||
64 | { DC_COM_PIN_OUTPUT_DATA(3), 0xaaaaaaaa }, | ||
65 | { DC_COM_PIN_OUTPUT_DATA(2), 0xaaaaaaaa }, | ||
66 | { DC_COM_PIN_OUTPUT_DATA(1), 0xaaaaaaaa }, | ||
67 | { DC_COM_PIN_OUTPUT_DATA(0), 0xaaaaaaaa }, | ||
68 | { DC_COM_PIN_OUTPUT_POLARITY(3), 0x00000000 }, | ||
69 | { DC_COM_PIN_OUTPUT_POLARITY(2), 0x00000000 }, | ||
70 | { DC_COM_PIN_OUTPUT_POLARITY(1), 0x00000000 }, | ||
71 | { DC_COM_PIN_OUTPUT_POLARITY(0), 0x00000000 }, | ||
72 | { DC_COM_PIN_OUTPUT_ENABLE(3), 0x55555555 }, | ||
73 | { DC_COM_PIN_OUTPUT_ENABLE(2), 0x55555555 }, | ||
74 | { DC_COM_PIN_OUTPUT_ENABLE(1), 0x55150005 }, | ||
75 | { DC_COM_PIN_OUTPUT_ENABLE(0), 0x55555555 }, | ||
76 | }; | ||
77 | |||
78 | static void tegra_dc_write_regs(struct tegra_dc *dc, | ||
79 | const struct reg_entry *table, | ||
80 | unsigned int num) | ||
81 | { | ||
82 | unsigned int i; | ||
83 | |||
84 | for (i = 0; i < num; i++) | ||
85 | tegra_dc_writel(dc, table[i].value, table[i].offset); | ||
86 | } | ||
87 | |||
88 | static int tegra_output_rgb_enable(struct tegra_output *output) | ||
89 | { | ||
90 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | ||
91 | |||
92 | tegra_dc_write_regs(dc, rgb_enable, ARRAY_SIZE(rgb_enable)); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int tegra_output_rgb_disable(struct tegra_output *output) | ||
98 | { | ||
99 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | ||
100 | |||
101 | tegra_dc_write_regs(dc, rgb_disable, ARRAY_SIZE(rgb_disable)); | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int tegra_output_rgb_setup_clock(struct tegra_output *output, | ||
107 | struct clk *clk, unsigned long pclk) | ||
108 | { | ||
109 | struct tegra_rgb *rgb = to_rgb(output); | ||
110 | |||
111 | return clk_set_parent(clk, rgb->clk_parent); | ||
112 | } | ||
113 | |||
114 | static int tegra_output_rgb_check_mode(struct tegra_output *output, | ||
115 | struct drm_display_mode *mode, | ||
116 | enum drm_mode_status *status) | ||
117 | { | ||
118 | /* | ||
119 | * FIXME: For now, always assume that the mode is okay. There are | ||
120 | * unresolved issues with clk_round_rate(), which doesn't always | ||
121 | * reliably report whether a frequency can be set or not. | ||
122 | */ | ||
123 | |||
124 | *status = MODE_OK; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static const struct tegra_output_ops rgb_ops = { | ||
130 | .enable = tegra_output_rgb_enable, | ||
131 | .disable = tegra_output_rgb_disable, | ||
132 | .setup_clock = tegra_output_rgb_setup_clock, | ||
133 | .check_mode = tegra_output_rgb_check_mode, | ||
134 | }; | ||
135 | |||
136 | int tegra_dc_rgb_probe(struct tegra_dc *dc) | ||
137 | { | ||
138 | struct device_node *np; | ||
139 | struct tegra_rgb *rgb; | ||
140 | int err; | ||
141 | |||
142 | np = of_get_child_by_name(dc->dev->of_node, "rgb"); | ||
143 | if (!np || !of_device_is_available(np)) | ||
144 | return -ENODEV; | ||
145 | |||
146 | rgb = devm_kzalloc(dc->dev, sizeof(*rgb), GFP_KERNEL); | ||
147 | if (!rgb) | ||
148 | return -ENOMEM; | ||
149 | |||
150 | rgb->output.dev = dc->dev; | ||
151 | rgb->output.of_node = np; | ||
152 | |||
153 | err = tegra_output_parse_dt(&rgb->output); | ||
154 | if (err < 0) | ||
155 | return err; | ||
156 | |||
157 | rgb->clk = devm_clk_get(dc->dev, NULL); | ||
158 | if (IS_ERR(rgb->clk)) { | ||
159 | dev_err(dc->dev, "failed to get clock\n"); | ||
160 | return PTR_ERR(rgb->clk); | ||
161 | } | ||
162 | |||
163 | rgb->clk_parent = devm_clk_get(dc->dev, "parent"); | ||
164 | if (IS_ERR(rgb->clk_parent)) { | ||
165 | dev_err(dc->dev, "failed to get parent clock\n"); | ||
166 | return PTR_ERR(rgb->clk_parent); | ||
167 | } | ||
168 | |||
169 | err = clk_set_parent(rgb->clk, rgb->clk_parent); | ||
170 | if (err < 0) { | ||
171 | dev_err(dc->dev, "failed to set parent clock: %d\n", err); | ||
172 | return err; | ||
173 | } | ||
174 | |||
175 | dc->rgb = &rgb->output; | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc) | ||
181 | { | ||
182 | struct tegra_rgb *rgb = to_rgb(dc->rgb); | ||
183 | int err; | ||
184 | |||
185 | if (!dc->rgb) | ||
186 | return -ENODEV; | ||
187 | |||
188 | rgb->output.type = TEGRA_OUTPUT_RGB; | ||
189 | rgb->output.ops = &rgb_ops; | ||
190 | |||
191 | err = tegra_output_init(dc->base.dev, &rgb->output); | ||
192 | if (err < 0) { | ||
193 | dev_err(dc->dev, "output setup failed: %d\n", err); | ||
194 | return err; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * By default, outputs can be associated with each display controller. | ||
199 | * RGB outputs are an exception, so we make sure they can be attached | ||
200 | * to only their parent display controller. | ||
201 | */ | ||
202 | rgb->output.encoder.possible_crtcs = 1 << dc->pipe; | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | int tegra_dc_rgb_exit(struct tegra_dc *dc) | ||
208 | { | ||
209 | if (dc->rgb) { | ||
210 | int err; | ||
211 | |||
212 | err = tegra_output_disable(dc->rgb); | ||
213 | if (err < 0) { | ||
214 | dev_err(dc->dev, "output failed to disable: %d\n", err); | ||
215 | return err; | ||
216 | } | ||
217 | |||
218 | err = tegra_output_exit(dc->rgb); | ||
219 | if (err < 0) { | ||
220 | dev_err(dc->dev, "output cleanup failed: %d\n", err); | ||
221 | return err; | ||
222 | } | ||
223 | |||
224 | dc->rgb = NULL; | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
diff --git a/drivers/gpu/host1x/host1x.h b/drivers/gpu/host1x/host1x.h deleted file mode 100644 index a2bc1e65e972..000000000000 --- a/drivers/gpu/host1x/host1x.h +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | /* | ||
2 | * Tegra host1x driver | ||
3 | * | ||
4 | * Copyright (c) 2009-2013, NVIDIA Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __LINUX_HOST1X_H | ||
22 | #define __LINUX_HOST1X_H | ||
23 | |||
24 | enum host1x_class { | ||
25 | HOST1X_CLASS_HOST1X = 0x1, | ||
26 | HOST1X_CLASS_GR2D = 0x51, | ||
27 | HOST1X_CLASS_GR2D_SB = 0x52 | ||
28 | }; | ||
29 | |||
30 | #endif | ||
diff --git a/drivers/gpu/host1x/host1x_bo.h b/drivers/gpu/host1x/host1x_bo.h deleted file mode 100644 index 4c1f10bd773d..000000000000 --- a/drivers/gpu/host1x/host1x_bo.h +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | /* | ||
2 | * Tegra host1x Memory Management Abstraction header | ||
3 | * | ||
4 | * Copyright (c) 2012-2013, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef _HOST1X_BO_H | ||
20 | #define _HOST1X_BO_H | ||
21 | |||
22 | struct host1x_bo; | ||
23 | |||
24 | struct host1x_bo_ops { | ||
25 | struct host1x_bo *(*get)(struct host1x_bo *bo); | ||
26 | void (*put)(struct host1x_bo *bo); | ||
27 | dma_addr_t (*pin)(struct host1x_bo *bo, struct sg_table **sgt); | ||
28 | void (*unpin)(struct host1x_bo *bo, struct sg_table *sgt); | ||
29 | void *(*mmap)(struct host1x_bo *bo); | ||
30 | void (*munmap)(struct host1x_bo *bo, void *addr); | ||
31 | void *(*kmap)(struct host1x_bo *bo, unsigned int pagenum); | ||
32 | void (*kunmap)(struct host1x_bo *bo, unsigned int pagenum, void *addr); | ||
33 | }; | ||
34 | |||
35 | struct host1x_bo { | ||
36 | const struct host1x_bo_ops *ops; | ||
37 | }; | ||
38 | |||
39 | static inline void host1x_bo_init(struct host1x_bo *bo, | ||
40 | const struct host1x_bo_ops *ops) | ||
41 | { | ||
42 | bo->ops = ops; | ||
43 | } | ||
44 | |||
45 | static inline struct host1x_bo *host1x_bo_get(struct host1x_bo *bo) | ||
46 | { | ||
47 | return bo->ops->get(bo); | ||
48 | } | ||
49 | |||
50 | static inline void host1x_bo_put(struct host1x_bo *bo) | ||
51 | { | ||
52 | bo->ops->put(bo); | ||
53 | } | ||
54 | |||
55 | static inline dma_addr_t host1x_bo_pin(struct host1x_bo *bo, | ||
56 | struct sg_table **sgt) | ||
57 | { | ||
58 | return bo->ops->pin(bo, sgt); | ||
59 | } | ||
60 | |||
61 | static inline void host1x_bo_unpin(struct host1x_bo *bo, struct sg_table *sgt) | ||
62 | { | ||
63 | bo->ops->unpin(bo, sgt); | ||
64 | } | ||
65 | |||
66 | static inline void *host1x_bo_mmap(struct host1x_bo *bo) | ||
67 | { | ||
68 | return bo->ops->mmap(bo); | ||
69 | } | ||
70 | |||
71 | static inline void host1x_bo_munmap(struct host1x_bo *bo, void *addr) | ||
72 | { | ||
73 | bo->ops->munmap(bo, addr); | ||
74 | } | ||
75 | |||
76 | static inline void *host1x_bo_kmap(struct host1x_bo *bo, unsigned int pagenum) | ||
77 | { | ||
78 | return bo->ops->kmap(bo, pagenum); | ||
79 | } | ||
80 | |||
81 | static inline void host1x_bo_kunmap(struct host1x_bo *bo, | ||
82 | unsigned int pagenum, void *addr) | ||
83 | { | ||
84 | bo->ops->kunmap(bo, pagenum, addr); | ||
85 | } | ||
86 | |||
87 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/Makefile b/drivers/gpu/host1x/hw/Makefile deleted file mode 100644 index 9b50863a2236..000000000000 --- a/drivers/gpu/host1x/hw/Makefile +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | ccflags-y = -Idrivers/gpu/host1x | ||
2 | |||
3 | host1x-hw-objs = \ | ||
4 | host1x01.o | ||
5 | |||
6 | obj-$(CONFIG_TEGRA_HOST1X) += host1x-hw.o | ||
diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c index 2ee4ad55c4db..37e2a63241a9 100644 --- a/drivers/gpu/host1x/hw/cdma_hw.c +++ b/drivers/gpu/host1x/hw/cdma_hw.c | |||
@@ -20,10 +20,10 @@ | |||
20 | #include <linux/scatterlist.h> | 20 | #include <linux/scatterlist.h> |
21 | #include <linux/dma-mapping.h> | 21 | #include <linux/dma-mapping.h> |
22 | 22 | ||
23 | #include "cdma.h" | 23 | #include "../cdma.h" |
24 | #include "channel.h" | 24 | #include "../channel.h" |
25 | #include "dev.h" | 25 | #include "../dev.h" |
26 | #include "debug.h" | 26 | #include "../debug.h" |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * Put the restart at the end of pushbuffer memor | 29 | * Put the restart at the end of pushbuffer memor |
diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c index ee199623e365..4608257ab656 100644 --- a/drivers/gpu/host1x/hw/channel_hw.c +++ b/drivers/gpu/host1x/hw/channel_hw.c | |||
@@ -16,15 +16,15 @@ | |||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/host1x.h> | ||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | |||
20 | #include <trace/events/host1x.h> | 22 | #include <trace/events/host1x.h> |
21 | 23 | ||
22 | #include "host1x.h" | 24 | #include "../channel.h" |
23 | #include "host1x_bo.h" | 25 | #include "../dev.h" |
24 | #include "channel.h" | 26 | #include "../intr.h" |
25 | #include "dev.h" | 27 | #include "../job.h" |
26 | #include "intr.h" | ||
27 | #include "job.h" | ||
28 | 28 | ||
29 | #define HOST1X_CHANNEL_SIZE 16384 | 29 | #define HOST1X_CHANNEL_SIZE 16384 |
30 | #define TRACE_MAX_LENGTH 128U | 30 | #define TRACE_MAX_LENGTH 128U |
@@ -67,6 +67,22 @@ static void submit_gathers(struct host1x_job *job) | |||
67 | } | 67 | } |
68 | } | 68 | } |
69 | 69 | ||
70 | static inline void synchronize_syncpt_base(struct host1x_job *job) | ||
71 | { | ||
72 | struct host1x *host = dev_get_drvdata(job->channel->dev->parent); | ||
73 | struct host1x_syncpt *sp = host->syncpt + job->syncpt_id; | ||
74 | u32 id, value; | ||
75 | |||
76 | value = host1x_syncpt_read_max(sp); | ||
77 | id = sp->base->id; | ||
78 | |||
79 | host1x_cdma_push(&job->channel->cdma, | ||
80 | host1x_opcode_setclass(HOST1X_CLASS_HOST1X, | ||
81 | HOST1X_UCLASS_LOAD_SYNCPT_BASE, 1), | ||
82 | HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(id) | | ||
83 | HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(value)); | ||
84 | } | ||
85 | |||
70 | static int channel_submit(struct host1x_job *job) | 86 | static int channel_submit(struct host1x_job *job) |
71 | { | 87 | { |
72 | struct host1x_channel *ch = job->channel; | 88 | struct host1x_channel *ch = job->channel; |
@@ -118,6 +134,10 @@ static int channel_submit(struct host1x_job *job) | |||
118 | host1x_syncpt_read_max(sp))); | 134 | host1x_syncpt_read_max(sp))); |
119 | } | 135 | } |
120 | 136 | ||
137 | /* Synchronize base register to allow using it for relative waiting */ | ||
138 | if (sp->base) | ||
139 | synchronize_syncpt_base(job); | ||
140 | |||
121 | syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs); | 141 | syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs); |
122 | 142 | ||
123 | job->syncpt_end = syncval; | 143 | job->syncpt_end = syncval; |
diff --git a/drivers/gpu/host1x/hw/debug_hw.c b/drivers/gpu/host1x/hw/debug_hw.c index 334c038052f5..640c75ca5a8b 100644 --- a/drivers/gpu/host1x/hw/debug_hw.c +++ b/drivers/gpu/host1x/hw/debug_hw.c | |||
@@ -15,18 +15,10 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/debugfs.h> | 18 | #include "../dev.h" |
19 | #include <linux/seq_file.h> | 19 | #include "../debug.h" |
20 | #include <linux/mm.h> | 20 | #include "../cdma.h" |
21 | #include <linux/scatterlist.h> | 21 | #include "../channel.h" |
22 | |||
23 | #include <linux/io.h> | ||
24 | |||
25 | #include "dev.h" | ||
26 | #include "debug.h" | ||
27 | #include "cdma.h" | ||
28 | #include "channel.h" | ||
29 | #include "host1x_bo.h" | ||
30 | 22 | ||
31 | #define HOST1X_DEBUG_MAX_PAGE_OFFSET 102400 | 23 | #define HOST1X_DEBUG_MAX_PAGE_OFFSET 102400 |
32 | 24 | ||
diff --git a/drivers/gpu/host1x/hw/host1x01.c b/drivers/gpu/host1x/hw/host1x01.c index a14e91cd1e58..859b73beb4d0 100644 --- a/drivers/gpu/host1x/hw/host1x01.c +++ b/drivers/gpu/host1x/hw/host1x01.c | |||
@@ -17,17 +17,17 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | /* include hw specification */ | 19 | /* include hw specification */ |
20 | #include "hw/host1x01.h" | 20 | #include "host1x01.h" |
21 | #include "hw/host1x01_hardware.h" | 21 | #include "host1x01_hardware.h" |
22 | 22 | ||
23 | /* include code */ | 23 | /* include code */ |
24 | #include "hw/cdma_hw.c" | 24 | #include "cdma_hw.c" |
25 | #include "hw/channel_hw.c" | 25 | #include "channel_hw.c" |
26 | #include "hw/debug_hw.c" | 26 | #include "debug_hw.c" |
27 | #include "hw/intr_hw.c" | 27 | #include "intr_hw.c" |
28 | #include "hw/syncpt_hw.c" | 28 | #include "syncpt_hw.c" |
29 | 29 | ||
30 | #include "dev.h" | 30 | #include "../dev.h" |
31 | 31 | ||
32 | int host1x01_init(struct host1x *host) | 32 | int host1x01_init(struct host1x *host) |
33 | { | 33 | { |
diff --git a/drivers/gpu/host1x/hw/host1x02.c b/drivers/gpu/host1x/hw/host1x02.c new file mode 100644 index 000000000000..e98caca0ca42 --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x02.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Host1x init for Tegra114 SoCs | ||
3 | * | ||
4 | * Copyright (c) 2013 NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | /* include hw specification */ | ||
20 | #include "host1x01.h" | ||
21 | #include "host1x01_hardware.h" | ||
22 | |||
23 | /* include code */ | ||
24 | #include "cdma_hw.c" | ||
25 | #include "channel_hw.c" | ||
26 | #include "debug_hw.c" | ||
27 | #include "intr_hw.c" | ||
28 | #include "syncpt_hw.c" | ||
29 | |||
30 | #include "../dev.h" | ||
31 | |||
32 | int host1x02_init(struct host1x *host) | ||
33 | { | ||
34 | host->channel_op = &host1x_channel_ops; | ||
35 | host->cdma_op = &host1x_cdma_ops; | ||
36 | host->cdma_pb_op = &host1x_pushbuffer_ops; | ||
37 | host->syncpt_op = &host1x_syncpt_ops; | ||
38 | host->intr_op = &host1x_intr_ops; | ||
39 | host->debug_op = &host1x_debug_ops; | ||
40 | |||
41 | return 0; | ||
42 | } | ||
diff --git a/drivers/gpu/host1x/hw/host1x02.h b/drivers/gpu/host1x/hw/host1x02.h new file mode 100644 index 000000000000..f7486609a90e --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x02.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Host1x init for Tegra114 SoCs | ||
3 | * | ||
4 | * Copyright (c) 2013 NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef HOST1X_HOST1X02_H | ||
20 | #define HOST1X_HOST1X02_H | ||
21 | |||
22 | struct host1x; | ||
23 | |||
24 | int host1x02_init(struct host1x *host); | ||
25 | |||
26 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x01_uclass.h b/drivers/gpu/host1x/hw/hw_host1x01_uclass.h index 42f3ce19ca32..f7553599ee27 100644 --- a/drivers/gpu/host1x/hw/hw_host1x01_uclass.h +++ b/drivers/gpu/host1x/hw/hw_host1x01_uclass.h | |||
@@ -111,6 +111,12 @@ static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v) | |||
111 | } | 111 | } |
112 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \ | 112 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \ |
113 | host1x_uclass_wait_syncpt_base_offset_f(v) | 113 | host1x_uclass_wait_syncpt_base_offset_f(v) |
114 | static inline u32 host1x_uclass_load_syncpt_base_r(void) | ||
115 | { | ||
116 | return 0xb; | ||
117 | } | ||
118 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE \ | ||
119 | host1x_uclass_load_syncpt_base_r() | ||
114 | static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v) | 120 | static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v) |
115 | { | 121 | { |
116 | return (v & 0xff) << 24; | 122 | return (v & 0xff) << 24; |
diff --git a/drivers/gpu/host1x/hw/hw_host1x02_channel.h b/drivers/gpu/host1x/hw/hw_host1x02_channel.h new file mode 100644 index 000000000000..e490bcde33fe --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x02_channel.h | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 NVIDIA Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * Function naming determines intended use: | ||
20 | * | ||
21 | * <x>_r(void) : Returns the offset for register <x>. | ||
22 | * | ||
23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
24 | * | ||
25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
26 | * | ||
27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
28 | * and masked to place it at field <y> of register <x>. This value | ||
29 | * can be |'d with others to produce a full register value for | ||
30 | * register <x>. | ||
31 | * | ||
32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
34 | * register <x>. | ||
35 | * | ||
36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
37 | * to place it at field <y> of register <x>. This value can be |'d | ||
38 | * with others to produce a full register value for <x>. | ||
39 | * | ||
40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
42 | * This value is suitable for direct comparison with other unshifted | ||
43 | * values appropriate for use in field <y> of register <x>. | ||
44 | * | ||
45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
46 | * field <y> of register <x>. This value is suitable for direct | ||
47 | * comparison with unshifted values appropriate for use in field <y> | ||
48 | * of register <x>. | ||
49 | */ | ||
50 | |||
51 | #ifndef HOST1X_HW_HOST1X02_CHANNEL_H | ||
52 | #define HOST1X_HW_HOST1X02_CHANNEL_H | ||
53 | |||
54 | static inline u32 host1x_channel_fifostat_r(void) | ||
55 | { | ||
56 | return 0x0; | ||
57 | } | ||
58 | #define HOST1X_CHANNEL_FIFOSTAT \ | ||
59 | host1x_channel_fifostat_r() | ||
60 | static inline u32 host1x_channel_fifostat_cfempty_v(u32 r) | ||
61 | { | ||
62 | return (r >> 11) & 0x1; | ||
63 | } | ||
64 | #define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(r) \ | ||
65 | host1x_channel_fifostat_cfempty_v(r) | ||
66 | static inline u32 host1x_channel_dmastart_r(void) | ||
67 | { | ||
68 | return 0x14; | ||
69 | } | ||
70 | #define HOST1X_CHANNEL_DMASTART \ | ||
71 | host1x_channel_dmastart_r() | ||
72 | static inline u32 host1x_channel_dmaput_r(void) | ||
73 | { | ||
74 | return 0x18; | ||
75 | } | ||
76 | #define HOST1X_CHANNEL_DMAPUT \ | ||
77 | host1x_channel_dmaput_r() | ||
78 | static inline u32 host1x_channel_dmaget_r(void) | ||
79 | { | ||
80 | return 0x1c; | ||
81 | } | ||
82 | #define HOST1X_CHANNEL_DMAGET \ | ||
83 | host1x_channel_dmaget_r() | ||
84 | static inline u32 host1x_channel_dmaend_r(void) | ||
85 | { | ||
86 | return 0x20; | ||
87 | } | ||
88 | #define HOST1X_CHANNEL_DMAEND \ | ||
89 | host1x_channel_dmaend_r() | ||
90 | static inline u32 host1x_channel_dmactrl_r(void) | ||
91 | { | ||
92 | return 0x24; | ||
93 | } | ||
94 | #define HOST1X_CHANNEL_DMACTRL \ | ||
95 | host1x_channel_dmactrl_r() | ||
96 | static inline u32 host1x_channel_dmactrl_dmastop(void) | ||
97 | { | ||
98 | return 1 << 0; | ||
99 | } | ||
100 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP \ | ||
101 | host1x_channel_dmactrl_dmastop() | ||
102 | static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r) | ||
103 | { | ||
104 | return (r >> 0) & 0x1; | ||
105 | } | ||
106 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \ | ||
107 | host1x_channel_dmactrl_dmastop_v(r) | ||
108 | static inline u32 host1x_channel_dmactrl_dmagetrst(void) | ||
109 | { | ||
110 | return 1 << 1; | ||
111 | } | ||
112 | #define HOST1X_CHANNEL_DMACTRL_DMAGETRST \ | ||
113 | host1x_channel_dmactrl_dmagetrst() | ||
114 | static inline u32 host1x_channel_dmactrl_dmainitget(void) | ||
115 | { | ||
116 | return 1 << 2; | ||
117 | } | ||
118 | #define HOST1X_CHANNEL_DMACTRL_DMAINITGET \ | ||
119 | host1x_channel_dmactrl_dmainitget() | ||
120 | |||
121 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x02_sync.h b/drivers/gpu/host1x/hw/hw_host1x02_sync.h new file mode 100644 index 000000000000..4495401525e8 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x02_sync.h | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 NVIDIA Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * Function naming determines intended use: | ||
20 | * | ||
21 | * <x>_r(void) : Returns the offset for register <x>. | ||
22 | * | ||
23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
24 | * | ||
25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
26 | * | ||
27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
28 | * and masked to place it at field <y> of register <x>. This value | ||
29 | * can be |'d with others to produce a full register value for | ||
30 | * register <x>. | ||
31 | * | ||
32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
34 | * register <x>. | ||
35 | * | ||
36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
37 | * to place it at field <y> of register <x>. This value can be |'d | ||
38 | * with others to produce a full register value for <x>. | ||
39 | * | ||
40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
42 | * This value is suitable for direct comparison with other unshifted | ||
43 | * values appropriate for use in field <y> of register <x>. | ||
44 | * | ||
45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
46 | * field <y> of register <x>. This value is suitable for direct | ||
47 | * comparison with unshifted values appropriate for use in field <y> | ||
48 | * of register <x>. | ||
49 | */ | ||
50 | |||
51 | #ifndef HOST1X_HW_HOST1X02_SYNC_H | ||
52 | #define HOST1X_HW_HOST1X02_SYNC_H | ||
53 | |||
54 | #define REGISTER_STRIDE 4 | ||
55 | |||
56 | static inline u32 host1x_sync_syncpt_r(unsigned int id) | ||
57 | { | ||
58 | return 0x400 + id * REGISTER_STRIDE; | ||
59 | } | ||
60 | #define HOST1X_SYNC_SYNCPT(id) \ | ||
61 | host1x_sync_syncpt_r(id) | ||
62 | static inline u32 host1x_sync_syncpt_thresh_cpu0_int_status_r(unsigned int id) | ||
63 | { | ||
64 | return 0x40 + id * REGISTER_STRIDE; | ||
65 | } | ||
66 | #define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id) \ | ||
67 | host1x_sync_syncpt_thresh_cpu0_int_status_r(id) | ||
68 | static inline u32 host1x_sync_syncpt_thresh_int_disable_r(unsigned int id) | ||
69 | { | ||
70 | return 0x60 + id * REGISTER_STRIDE; | ||
71 | } | ||
72 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id) \ | ||
73 | host1x_sync_syncpt_thresh_int_disable_r(id) | ||
74 | static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(unsigned int id) | ||
75 | { | ||
76 | return 0x68 + id * REGISTER_STRIDE; | ||
77 | } | ||
78 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \ | ||
79 | host1x_sync_syncpt_thresh_int_enable_cpu0_r(id) | ||
80 | static inline u32 host1x_sync_cf_setup_r(unsigned int channel) | ||
81 | { | ||
82 | return 0x80 + channel * REGISTER_STRIDE; | ||
83 | } | ||
84 | #define HOST1X_SYNC_CF_SETUP(channel) \ | ||
85 | host1x_sync_cf_setup_r(channel) | ||
86 | static inline u32 host1x_sync_cf_setup_base_v(u32 r) | ||
87 | { | ||
88 | return (r >> 0) & 0x3ff; | ||
89 | } | ||
90 | #define HOST1X_SYNC_CF_SETUP_BASE_V(r) \ | ||
91 | host1x_sync_cf_setup_base_v(r) | ||
92 | static inline u32 host1x_sync_cf_setup_limit_v(u32 r) | ||
93 | { | ||
94 | return (r >> 16) & 0x3ff; | ||
95 | } | ||
96 | #define HOST1X_SYNC_CF_SETUP_LIMIT_V(r) \ | ||
97 | host1x_sync_cf_setup_limit_v(r) | ||
98 | static inline u32 host1x_sync_cmdproc_stop_r(void) | ||
99 | { | ||
100 | return 0xac; | ||
101 | } | ||
102 | #define HOST1X_SYNC_CMDPROC_STOP \ | ||
103 | host1x_sync_cmdproc_stop_r() | ||
104 | static inline u32 host1x_sync_ch_teardown_r(void) | ||
105 | { | ||
106 | return 0xb0; | ||
107 | } | ||
108 | #define HOST1X_SYNC_CH_TEARDOWN \ | ||
109 | host1x_sync_ch_teardown_r() | ||
110 | static inline u32 host1x_sync_usec_clk_r(void) | ||
111 | { | ||
112 | return 0x1a4; | ||
113 | } | ||
114 | #define HOST1X_SYNC_USEC_CLK \ | ||
115 | host1x_sync_usec_clk_r() | ||
116 | static inline u32 host1x_sync_ctxsw_timeout_cfg_r(void) | ||
117 | { | ||
118 | return 0x1a8; | ||
119 | } | ||
120 | #define HOST1X_SYNC_CTXSW_TIMEOUT_CFG \ | ||
121 | host1x_sync_ctxsw_timeout_cfg_r() | ||
122 | static inline u32 host1x_sync_ip_busy_timeout_r(void) | ||
123 | { | ||
124 | return 0x1bc; | ||
125 | } | ||
126 | #define HOST1X_SYNC_IP_BUSY_TIMEOUT \ | ||
127 | host1x_sync_ip_busy_timeout_r() | ||
128 | static inline u32 host1x_sync_mlock_owner_r(unsigned int id) | ||
129 | { | ||
130 | return 0x340 + id * REGISTER_STRIDE; | ||
131 | } | ||
132 | #define HOST1X_SYNC_MLOCK_OWNER(id) \ | ||
133 | host1x_sync_mlock_owner_r(id) | ||
134 | static inline u32 host1x_sync_mlock_owner_chid_f(u32 v) | ||
135 | { | ||
136 | return (v & 0xf) << 8; | ||
137 | } | ||
138 | #define HOST1X_SYNC_MLOCK_OWNER_CHID_F(v) \ | ||
139 | host1x_sync_mlock_owner_chid_f(v) | ||
140 | static inline u32 host1x_sync_mlock_owner_cpu_owns_v(u32 r) | ||
141 | { | ||
142 | return (r >> 1) & 0x1; | ||
143 | } | ||
144 | #define HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(r) \ | ||
145 | host1x_sync_mlock_owner_cpu_owns_v(r) | ||
146 | static inline u32 host1x_sync_mlock_owner_ch_owns_v(u32 r) | ||
147 | { | ||
148 | return (r >> 0) & 0x1; | ||
149 | } | ||
150 | #define HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(r) \ | ||
151 | host1x_sync_mlock_owner_ch_owns_v(r) | ||
152 | static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id) | ||
153 | { | ||
154 | return 0x500 + id * REGISTER_STRIDE; | ||
155 | } | ||
156 | #define HOST1X_SYNC_SYNCPT_INT_THRESH(id) \ | ||
157 | host1x_sync_syncpt_int_thresh_r(id) | ||
158 | static inline u32 host1x_sync_syncpt_base_r(unsigned int id) | ||
159 | { | ||
160 | return 0x600 + id * REGISTER_STRIDE; | ||
161 | } | ||
162 | #define HOST1X_SYNC_SYNCPT_BASE(id) \ | ||
163 | host1x_sync_syncpt_base_r(id) | ||
164 | static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id) | ||
165 | { | ||
166 | return 0x700 + id * REGISTER_STRIDE; | ||
167 | } | ||
168 | #define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \ | ||
169 | host1x_sync_syncpt_cpu_incr_r(id) | ||
170 | static inline u32 host1x_sync_cbread_r(unsigned int channel) | ||
171 | { | ||
172 | return 0x720 + channel * REGISTER_STRIDE; | ||
173 | } | ||
174 | #define HOST1X_SYNC_CBREAD(channel) \ | ||
175 | host1x_sync_cbread_r(channel) | ||
176 | static inline u32 host1x_sync_cfpeek_ctrl_r(void) | ||
177 | { | ||
178 | return 0x74c; | ||
179 | } | ||
180 | #define HOST1X_SYNC_CFPEEK_CTRL \ | ||
181 | host1x_sync_cfpeek_ctrl_r() | ||
182 | static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v) | ||
183 | { | ||
184 | return (v & 0x3ff) << 0; | ||
185 | } | ||
186 | #define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \ | ||
187 | host1x_sync_cfpeek_ctrl_addr_f(v) | ||
188 | static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v) | ||
189 | { | ||
190 | return (v & 0xf) << 16; | ||
191 | } | ||
192 | #define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \ | ||
193 | host1x_sync_cfpeek_ctrl_channr_f(v) | ||
194 | static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v) | ||
195 | { | ||
196 | return (v & 0x1) << 31; | ||
197 | } | ||
198 | #define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \ | ||
199 | host1x_sync_cfpeek_ctrl_ena_f(v) | ||
200 | static inline u32 host1x_sync_cfpeek_read_r(void) | ||
201 | { | ||
202 | return 0x750; | ||
203 | } | ||
204 | #define HOST1X_SYNC_CFPEEK_READ \ | ||
205 | host1x_sync_cfpeek_read_r() | ||
206 | static inline u32 host1x_sync_cfpeek_ptrs_r(void) | ||
207 | { | ||
208 | return 0x754; | ||
209 | } | ||
210 | #define HOST1X_SYNC_CFPEEK_PTRS \ | ||
211 | host1x_sync_cfpeek_ptrs_r() | ||
212 | static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r) | ||
213 | { | ||
214 | return (r >> 0) & 0x3ff; | ||
215 | } | ||
216 | #define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \ | ||
217 | host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r) | ||
218 | static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r) | ||
219 | { | ||
220 | return (r >> 16) & 0x3ff; | ||
221 | } | ||
222 | #define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \ | ||
223 | host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r) | ||
224 | static inline u32 host1x_sync_cbstat_r(unsigned int channel) | ||
225 | { | ||
226 | return 0x758 + channel * REGISTER_STRIDE; | ||
227 | } | ||
228 | #define HOST1X_SYNC_CBSTAT(channel) \ | ||
229 | host1x_sync_cbstat_r(channel) | ||
230 | static inline u32 host1x_sync_cbstat_cboffset_v(u32 r) | ||
231 | { | ||
232 | return (r >> 0) & 0xffff; | ||
233 | } | ||
234 | #define HOST1X_SYNC_CBSTAT_CBOFFSET_V(r) \ | ||
235 | host1x_sync_cbstat_cboffset_v(r) | ||
236 | static inline u32 host1x_sync_cbstat_cbclass_v(u32 r) | ||
237 | { | ||
238 | return (r >> 16) & 0x3ff; | ||
239 | } | ||
240 | #define HOST1X_SYNC_CBSTAT_CBCLASS_V(r) \ | ||
241 | host1x_sync_cbstat_cbclass_v(r) | ||
242 | |||
243 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x02_uclass.h b/drivers/gpu/host1x/hw/hw_host1x02_uclass.h new file mode 100644 index 000000000000..a3b3c9874413 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x02_uclass.h | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 NVIDIA Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * Function naming determines intended use: | ||
20 | * | ||
21 | * <x>_r(void) : Returns the offset for register <x>. | ||
22 | * | ||
23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
24 | * | ||
25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
26 | * | ||
27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
28 | * and masked to place it at field <y> of register <x>. This value | ||
29 | * can be |'d with others to produce a full register value for | ||
30 | * register <x>. | ||
31 | * | ||
32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
34 | * register <x>. | ||
35 | * | ||
36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
37 | * to place it at field <y> of register <x>. This value can be |'d | ||
38 | * with others to produce a full register value for <x>. | ||
39 | * | ||
40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
42 | * This value is suitable for direct comparison with other unshifted | ||
43 | * values appropriate for use in field <y> of register <x>. | ||
44 | * | ||
45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
46 | * field <y> of register <x>. This value is suitable for direct | ||
47 | * comparison with unshifted values appropriate for use in field <y> | ||
48 | * of register <x>. | ||
49 | */ | ||
50 | |||
51 | #ifndef HOST1X_HW_HOST1X02_UCLASS_H | ||
52 | #define HOST1X_HW_HOST1X02_UCLASS_H | ||
53 | |||
54 | static inline u32 host1x_uclass_incr_syncpt_r(void) | ||
55 | { | ||
56 | return 0x0; | ||
57 | } | ||
58 | #define HOST1X_UCLASS_INCR_SYNCPT \ | ||
59 | host1x_uclass_incr_syncpt_r() | ||
60 | static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v) | ||
61 | { | ||
62 | return (v & 0xff) << 8; | ||
63 | } | ||
64 | #define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \ | ||
65 | host1x_uclass_incr_syncpt_cond_f(v) | ||
66 | static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v) | ||
67 | { | ||
68 | return (v & 0xff) << 0; | ||
69 | } | ||
70 | #define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \ | ||
71 | host1x_uclass_incr_syncpt_indx_f(v) | ||
72 | static inline u32 host1x_uclass_wait_syncpt_r(void) | ||
73 | { | ||
74 | return 0x8; | ||
75 | } | ||
76 | #define HOST1X_UCLASS_WAIT_SYNCPT \ | ||
77 | host1x_uclass_wait_syncpt_r() | ||
78 | static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v) | ||
79 | { | ||
80 | return (v & 0xff) << 24; | ||
81 | } | ||
82 | #define HOST1X_UCLASS_WAIT_SYNCPT_INDX_F(v) \ | ||
83 | host1x_uclass_wait_syncpt_indx_f(v) | ||
84 | static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v) | ||
85 | { | ||
86 | return (v & 0xffffff) << 0; | ||
87 | } | ||
88 | #define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \ | ||
89 | host1x_uclass_wait_syncpt_thresh_f(v) | ||
90 | static inline u32 host1x_uclass_wait_syncpt_base_r(void) | ||
91 | { | ||
92 | return 0x9; | ||
93 | } | ||
94 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE \ | ||
95 | host1x_uclass_wait_syncpt_base_r() | ||
96 | static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v) | ||
97 | { | ||
98 | return (v & 0xff) << 24; | ||
99 | } | ||
100 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_INDX_F(v) \ | ||
101 | host1x_uclass_wait_syncpt_base_indx_f(v) | ||
102 | static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v) | ||
103 | { | ||
104 | return (v & 0xff) << 16; | ||
105 | } | ||
106 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
107 | host1x_uclass_wait_syncpt_base_base_indx_f(v) | ||
108 | static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v) | ||
109 | { | ||
110 | return (v & 0xffff) << 0; | ||
111 | } | ||
112 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \ | ||
113 | host1x_uclass_wait_syncpt_base_offset_f(v) | ||
114 | static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v) | ||
115 | { | ||
116 | return (v & 0xff) << 24; | ||
117 | } | ||
118 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
119 | host1x_uclass_load_syncpt_base_base_indx_f(v) | ||
120 | static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v) | ||
121 | { | ||
122 | return (v & 0xffffff) << 0; | ||
123 | } | ||
124 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(v) \ | ||
125 | host1x_uclass_load_syncpt_base_value_f(v) | ||
126 | static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v) | ||
127 | { | ||
128 | return (v & 0xff) << 24; | ||
129 | } | ||
130 | #define HOST1X_UCLASS_INCR_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
131 | host1x_uclass_incr_syncpt_base_base_indx_f(v) | ||
132 | static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v) | ||
133 | { | ||
134 | return (v & 0xffffff) << 0; | ||
135 | } | ||
136 | #define HOST1X_UCLASS_INCR_SYNCPT_BASE_OFFSET_F(v) \ | ||
137 | host1x_uclass_incr_syncpt_base_offset_f(v) | ||
138 | static inline u32 host1x_uclass_indoff_r(void) | ||
139 | { | ||
140 | return 0x2d; | ||
141 | } | ||
142 | #define HOST1X_UCLASS_INDOFF \ | ||
143 | host1x_uclass_indoff_r() | ||
144 | static inline u32 host1x_uclass_indoff_indbe_f(u32 v) | ||
145 | { | ||
146 | return (v & 0xf) << 28; | ||
147 | } | ||
148 | #define HOST1X_UCLASS_INDOFF_INDBE_F(v) \ | ||
149 | host1x_uclass_indoff_indbe_f(v) | ||
150 | static inline u32 host1x_uclass_indoff_autoinc_f(u32 v) | ||
151 | { | ||
152 | return (v & 0x1) << 27; | ||
153 | } | ||
154 | #define HOST1X_UCLASS_INDOFF_AUTOINC_F(v) \ | ||
155 | host1x_uclass_indoff_autoinc_f(v) | ||
156 | static inline u32 host1x_uclass_indoff_indmodid_f(u32 v) | ||
157 | { | ||
158 | return (v & 0xff) << 18; | ||
159 | } | ||
160 | #define HOST1X_UCLASS_INDOFF_INDMODID_F(v) \ | ||
161 | host1x_uclass_indoff_indmodid_f(v) | ||
162 | static inline u32 host1x_uclass_indoff_indroffset_f(u32 v) | ||
163 | { | ||
164 | return (v & 0xffff) << 2; | ||
165 | } | ||
166 | #define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ | ||
167 | host1x_uclass_indoff_indroffset_f(v) | ||
168 | static inline u32 host1x_uclass_indoff_rwn_read_v(void) | ||
169 | { | ||
170 | return 1; | ||
171 | } | ||
172 | #define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ | ||
173 | host1x_uclass_indoff_indroffset_f(v) | ||
174 | |||
175 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c index b592eef1efcb..b26dcc83bc1b 100644 --- a/drivers/gpu/host1x/hw/intr_hw.c +++ b/drivers/gpu/host1x/hw/intr_hw.c | |||
@@ -22,8 +22,8 @@ | |||
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <asm/mach/irq.h> | 23 | #include <asm/mach/irq.h> |
24 | 24 | ||
25 | #include "intr.h" | 25 | #include "../intr.h" |
26 | #include "dev.h" | 26 | #include "../dev.h" |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * Sync point threshold interrupt service function | 29 | * Sync point threshold interrupt service function |
diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c index 0cf6095d3367..56e85395ac24 100644 --- a/drivers/gpu/host1x/hw/syncpt_hw.c +++ b/drivers/gpu/host1x/hw/syncpt_hw.c | |||
@@ -18,8 +18,8 @@ | |||
18 | 18 | ||
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | 20 | ||
21 | #include "dev.h" | 21 | #include "../dev.h" |
22 | #include "syncpt.h" | 22 | #include "../syncpt.h" |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * Write the current syncpoint value back to hw. | 25 | * Write the current syncpoint value back to hw. |
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index c4e1050f2252..de5ec333ce1a 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
20 | #include <linux/err.h> | 20 | #include <linux/err.h> |
21 | #include <linux/host1x.h> | ||
21 | #include <linux/kref.h> | 22 | #include <linux/kref.h> |
22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
23 | #include <linux/scatterlist.h> | 24 | #include <linux/scatterlist.h> |
@@ -27,7 +28,6 @@ | |||
27 | 28 | ||
28 | #include "channel.h" | 29 | #include "channel.h" |
29 | #include "dev.h" | 30 | #include "dev.h" |
30 | #include "host1x_bo.h" | ||
31 | #include "job.h" | 31 | #include "job.h" |
32 | #include "syncpt.h" | 32 | #include "syncpt.h" |
33 | 33 | ||
@@ -264,7 +264,7 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf) | |||
264 | } | 264 | } |
265 | 265 | ||
266 | static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf, | 266 | static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf, |
267 | unsigned int offset) | 267 | unsigned int offset) |
268 | { | 268 | { |
269 | offset *= sizeof(u32); | 269 | offset *= sizeof(u32); |
270 | 270 | ||
@@ -281,7 +281,7 @@ struct host1x_firewall { | |||
281 | unsigned int num_relocs; | 281 | unsigned int num_relocs; |
282 | struct host1x_reloc *reloc; | 282 | struct host1x_reloc *reloc; |
283 | 283 | ||
284 | struct host1x_bo *cmdbuf_id; | 284 | struct host1x_bo *cmdbuf; |
285 | unsigned int offset; | 285 | unsigned int offset; |
286 | 286 | ||
287 | u32 words; | 287 | u32 words; |
@@ -291,25 +291,37 @@ struct host1x_firewall { | |||
291 | u32 count; | 291 | u32 count; |
292 | }; | 292 | }; |
293 | 293 | ||
294 | static int check_register(struct host1x_firewall *fw, unsigned long offset) | ||
295 | { | ||
296 | if (fw->job->is_addr_reg(fw->dev, fw->class, offset)) { | ||
297 | if (!fw->num_relocs) | ||
298 | return -EINVAL; | ||
299 | |||
300 | if (!check_reloc(fw->reloc, fw->cmdbuf, fw->offset)) | ||
301 | return -EINVAL; | ||
302 | |||
303 | fw->num_relocs--; | ||
304 | fw->reloc++; | ||
305 | } | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
294 | static int check_mask(struct host1x_firewall *fw) | 310 | static int check_mask(struct host1x_firewall *fw) |
295 | { | 311 | { |
296 | u32 mask = fw->mask; | 312 | u32 mask = fw->mask; |
297 | u32 reg = fw->reg; | 313 | u32 reg = fw->reg; |
314 | int ret; | ||
298 | 315 | ||
299 | while (mask) { | 316 | while (mask) { |
300 | if (fw->words == 0) | 317 | if (fw->words == 0) |
301 | return -EINVAL; | 318 | return -EINVAL; |
302 | 319 | ||
303 | if (mask & 1) { | 320 | if (mask & 1) { |
304 | if (fw->job->is_addr_reg(fw->dev, fw->class, reg)) { | 321 | ret = check_register(fw, reg); |
305 | if (!fw->num_relocs) | 322 | if (ret < 0) |
306 | return -EINVAL; | 323 | return ret; |
307 | if (!check_reloc(fw->reloc, fw->cmdbuf_id, | 324 | |
308 | fw->offset)) | ||
309 | return -EINVAL; | ||
310 | fw->reloc++; | ||
311 | fw->num_relocs--; | ||
312 | } | ||
313 | fw->words--; | 325 | fw->words--; |
314 | fw->offset++; | 326 | fw->offset++; |
315 | } | 327 | } |
@@ -324,19 +336,16 @@ static int check_incr(struct host1x_firewall *fw) | |||
324 | { | 336 | { |
325 | u32 count = fw->count; | 337 | u32 count = fw->count; |
326 | u32 reg = fw->reg; | 338 | u32 reg = fw->reg; |
339 | int ret; | ||
327 | 340 | ||
328 | while (count) { | 341 | while (count) { |
329 | if (fw->words == 0) | 342 | if (fw->words == 0) |
330 | return -EINVAL; | 343 | return -EINVAL; |
331 | 344 | ||
332 | if (fw->job->is_addr_reg(fw->dev, fw->class, reg)) { | 345 | ret = check_register(fw, reg); |
333 | if (!fw->num_relocs) | 346 | if (ret < 0) |
334 | return -EINVAL; | 347 | return ret; |
335 | if (!check_reloc(fw->reloc, fw->cmdbuf_id, fw->offset)) | 348 | |
336 | return -EINVAL; | ||
337 | fw->reloc++; | ||
338 | fw->num_relocs--; | ||
339 | } | ||
340 | reg++; | 349 | reg++; |
341 | fw->words--; | 350 | fw->words--; |
342 | fw->offset++; | 351 | fw->offset++; |
@@ -348,21 +357,17 @@ static int check_incr(struct host1x_firewall *fw) | |||
348 | 357 | ||
349 | static int check_nonincr(struct host1x_firewall *fw) | 358 | static int check_nonincr(struct host1x_firewall *fw) |
350 | { | 359 | { |
351 | int is_addr_reg = fw->job->is_addr_reg(fw->dev, fw->class, fw->reg); | ||
352 | u32 count = fw->count; | 360 | u32 count = fw->count; |
361 | int ret; | ||
353 | 362 | ||
354 | while (count) { | 363 | while (count) { |
355 | if (fw->words == 0) | 364 | if (fw->words == 0) |
356 | return -EINVAL; | 365 | return -EINVAL; |
357 | 366 | ||
358 | if (is_addr_reg) { | 367 | ret = check_register(fw, fw->reg); |
359 | if (!fw->num_relocs) | 368 | if (ret < 0) |
360 | return -EINVAL; | 369 | return ret; |
361 | if (!check_reloc(fw->reloc, fw->cmdbuf_id, fw->offset)) | 370 | |
362 | return -EINVAL; | ||
363 | fw->reloc++; | ||
364 | fw->num_relocs--; | ||
365 | } | ||
366 | fw->words--; | 371 | fw->words--; |
367 | fw->offset++; | 372 | fw->offset++; |
368 | count--; | 373 | count--; |
@@ -381,7 +386,7 @@ static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g) | |||
381 | return 0; | 386 | return 0; |
382 | 387 | ||
383 | fw->words = g->words; | 388 | fw->words = g->words; |
384 | fw->cmdbuf_id = g->bo; | 389 | fw->cmdbuf = g->bo; |
385 | fw->offset = 0; | 390 | fw->offset = 0; |
386 | 391 | ||
387 | while (fw->words && !err) { | 392 | while (fw->words && !err) { |
@@ -436,10 +441,6 @@ static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g) | |||
436 | } | 441 | } |
437 | } | 442 | } |
438 | 443 | ||
439 | /* No relocs should remain at this point */ | ||
440 | if (fw->num_relocs) | ||
441 | err = -EINVAL; | ||
442 | |||
443 | out: | 444 | out: |
444 | return err; | 445 | return err; |
445 | } | 446 | } |
@@ -493,6 +494,10 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev) | |||
493 | offset += g->words * sizeof(u32); | 494 | offset += g->words * sizeof(u32); |
494 | } | 495 | } |
495 | 496 | ||
497 | /* No relocs should remain at this point */ | ||
498 | if (fw.num_relocs) | ||
499 | return -EINVAL; | ||
500 | |||
496 | return 0; | 501 | return 0; |
497 | } | 502 | } |
498 | 503 | ||
diff --git a/drivers/gpu/host1x/job.h b/drivers/gpu/host1x/job.h index fba45f20458e..33a697d6dcef 100644 --- a/drivers/gpu/host1x/job.h +++ b/drivers/gpu/host1x/job.h | |||
@@ -34,15 +34,6 @@ struct host1x_cmdbuf { | |||
34 | u32 pad; | 34 | u32 pad; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | struct host1x_reloc { | ||
38 | struct host1x_bo *cmdbuf; | ||
39 | u32 cmdbuf_offset; | ||
40 | struct host1x_bo *target; | ||
41 | u32 target_offset; | ||
42 | u32 shift; | ||
43 | u32 pad; | ||
44 | }; | ||
45 | |||
46 | struct host1x_waitchk { | 37 | struct host1x_waitchk { |
47 | struct host1x_bo *bo; | 38 | struct host1x_bo *bo; |
48 | u32 offset; | 39 | u32 offset; |
@@ -56,105 +47,6 @@ struct host1x_job_unpin_data { | |||
56 | }; | 47 | }; |
57 | 48 | ||
58 | /* | 49 | /* |
59 | * Each submit is tracked as a host1x_job. | ||
60 | */ | ||
61 | struct host1x_job { | ||
62 | /* When refcount goes to zero, job can be freed */ | ||
63 | struct kref ref; | ||
64 | |||
65 | /* List entry */ | ||
66 | struct list_head list; | ||
67 | |||
68 | /* Channel where job is submitted to */ | ||
69 | struct host1x_channel *channel; | ||
70 | |||
71 | u32 client; | ||
72 | |||
73 | /* Gathers and their memory */ | ||
74 | struct host1x_job_gather *gathers; | ||
75 | unsigned int num_gathers; | ||
76 | |||
77 | /* Wait checks to be processed at submit time */ | ||
78 | struct host1x_waitchk *waitchk; | ||
79 | unsigned int num_waitchk; | ||
80 | u32 waitchk_mask; | ||
81 | |||
82 | /* Array of handles to be pinned & unpinned */ | ||
83 | struct host1x_reloc *relocarray; | ||
84 | unsigned int num_relocs; | ||
85 | struct host1x_job_unpin_data *unpins; | ||
86 | unsigned int num_unpins; | ||
87 | |||
88 | dma_addr_t *addr_phys; | ||
89 | dma_addr_t *gather_addr_phys; | ||
90 | dma_addr_t *reloc_addr_phys; | ||
91 | |||
92 | /* Sync point id, number of increments and end related to the submit */ | ||
93 | u32 syncpt_id; | ||
94 | u32 syncpt_incrs; | ||
95 | u32 syncpt_end; | ||
96 | |||
97 | /* Maximum time to wait for this job */ | ||
98 | unsigned int timeout; | ||
99 | |||
100 | /* Index and number of slots used in the push buffer */ | ||
101 | unsigned int first_get; | ||
102 | unsigned int num_slots; | ||
103 | |||
104 | /* Copy of gathers */ | ||
105 | size_t gather_copy_size; | ||
106 | dma_addr_t gather_copy; | ||
107 | u8 *gather_copy_mapped; | ||
108 | |||
109 | /* Check if register is marked as an address reg */ | ||
110 | int (*is_addr_reg)(struct device *dev, u32 reg, u32 class); | ||
111 | |||
112 | /* Request a SETCLASS to this class */ | ||
113 | u32 class; | ||
114 | |||
115 | /* Add a channel wait for previous ops to complete */ | ||
116 | bool serialize; | ||
117 | }; | ||
118 | /* | ||
119 | * Allocate memory for a job. Just enough memory will be allocated to | ||
120 | * accomodate the submit. | ||
121 | */ | ||
122 | struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, | ||
123 | u32 num_cmdbufs, u32 num_relocs, | ||
124 | u32 num_waitchks); | ||
125 | |||
126 | /* | ||
127 | * Add a gather to a job. | ||
128 | */ | ||
129 | void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *mem_id, | ||
130 | u32 words, u32 offset); | ||
131 | |||
132 | /* | ||
133 | * Increment reference going to host1x_job. | ||
134 | */ | ||
135 | struct host1x_job *host1x_job_get(struct host1x_job *job); | ||
136 | |||
137 | /* | ||
138 | * Decrement reference job, free if goes to zero. | ||
139 | */ | ||
140 | void host1x_job_put(struct host1x_job *job); | ||
141 | |||
142 | /* | ||
143 | * Pin memory related to job. This handles relocation of addresses to the | ||
144 | * host1x address space. Handles both the gather memory and any other memory | ||
145 | * referred to from the gather buffers. | ||
146 | * | ||
147 | * Handles also patching out host waits that would wait for an expired sync | ||
148 | * point value. | ||
149 | */ | ||
150 | int host1x_job_pin(struct host1x_job *job, struct device *dev); | ||
151 | |||
152 | /* | ||
153 | * Unpin memory related to job. | ||
154 | */ | ||
155 | void host1x_job_unpin(struct host1x_job *job); | ||
156 | |||
157 | /* | ||
158 | * Dump contents of job to debug output. | 50 | * Dump contents of job to debug output. |
159 | */ | 51 | */ |
160 | void host1x_job_dump(struct device *dev, struct host1x_job *job); | 52 | void host1x_job_dump(struct device *dev, struct host1x_job *job); |
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index 409745b949db..159c479829c9 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c | |||
@@ -30,9 +30,32 @@ | |||
30 | #define SYNCPT_CHECK_PERIOD (2 * HZ) | 30 | #define SYNCPT_CHECK_PERIOD (2 * HZ) |
31 | #define MAX_STUCK_CHECK_COUNT 15 | 31 | #define MAX_STUCK_CHECK_COUNT 15 |
32 | 32 | ||
33 | static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host, | 33 | static struct host1x_syncpt_base * |
34 | struct device *dev, | 34 | host1x_syncpt_base_request(struct host1x *host) |
35 | bool client_managed) | 35 | { |
36 | struct host1x_syncpt_base *bases = host->bases; | ||
37 | unsigned int i; | ||
38 | |||
39 | for (i = 0; i < host->info->nb_bases; i++) | ||
40 | if (!bases[i].requested) | ||
41 | break; | ||
42 | |||
43 | if (i >= host->info->nb_bases) | ||
44 | return NULL; | ||
45 | |||
46 | bases[i].requested = true; | ||
47 | return &bases[i]; | ||
48 | } | ||
49 | |||
50 | static void host1x_syncpt_base_free(struct host1x_syncpt_base *base) | ||
51 | { | ||
52 | if (base) | ||
53 | base->requested = false; | ||
54 | } | ||
55 | |||
56 | static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, | ||
57 | struct device *dev, | ||
58 | unsigned long flags) | ||
36 | { | 59 | { |
37 | int i; | 60 | int i; |
38 | struct host1x_syncpt *sp = host->syncpt; | 61 | struct host1x_syncpt *sp = host->syncpt; |
@@ -44,6 +67,12 @@ static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host, | |||
44 | if (i >= host->info->nb_pts) | 67 | if (i >= host->info->nb_pts) |
45 | return NULL; | 68 | return NULL; |
46 | 69 | ||
70 | if (flags & HOST1X_SYNCPT_HAS_BASE) { | ||
71 | sp->base = host1x_syncpt_base_request(host); | ||
72 | if (!sp->base) | ||
73 | return NULL; | ||
74 | } | ||
75 | |||
47 | name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id, | 76 | name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id, |
48 | dev ? dev_name(dev) : NULL); | 77 | dev ? dev_name(dev) : NULL); |
49 | if (!name) | 78 | if (!name) |
@@ -51,7 +80,11 @@ static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host, | |||
51 | 80 | ||
52 | sp->dev = dev; | 81 | sp->dev = dev; |
53 | sp->name = name; | 82 | sp->name = name; |
54 | sp->client_managed = client_managed; | 83 | |
84 | if (flags & HOST1X_SYNCPT_CLIENT_MANAGED) | ||
85 | sp->client_managed = true; | ||
86 | else | ||
87 | sp->client_managed = false; | ||
55 | 88 | ||
56 | return sp; | 89 | return sp; |
57 | } | 90 | } |
@@ -303,25 +336,35 @@ int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr) | |||
303 | 336 | ||
304 | int host1x_syncpt_init(struct host1x *host) | 337 | int host1x_syncpt_init(struct host1x *host) |
305 | { | 338 | { |
339 | struct host1x_syncpt_base *bases; | ||
306 | struct host1x_syncpt *syncpt; | 340 | struct host1x_syncpt *syncpt; |
307 | int i; | 341 | int i; |
308 | 342 | ||
309 | syncpt = devm_kzalloc(host->dev, sizeof(*syncpt) * host->info->nb_pts, | 343 | syncpt = devm_kzalloc(host->dev, sizeof(*syncpt) * host->info->nb_pts, |
310 | GFP_KERNEL); | 344 | GFP_KERNEL); |
311 | if (!syncpt) | 345 | if (!syncpt) |
312 | return -ENOMEM; | 346 | return -ENOMEM; |
313 | 347 | ||
314 | for (i = 0; i < host->info->nb_pts; ++i) { | 348 | bases = devm_kzalloc(host->dev, sizeof(*bases) * host->info->nb_bases, |
349 | GFP_KERNEL); | ||
350 | if (!bases) | ||
351 | return -ENOMEM; | ||
352 | |||
353 | for (i = 0; i < host->info->nb_pts; i++) { | ||
315 | syncpt[i].id = i; | 354 | syncpt[i].id = i; |
316 | syncpt[i].host = host; | 355 | syncpt[i].host = host; |
317 | } | 356 | } |
318 | 357 | ||
358 | for (i = 0; i < host->info->nb_bases; i++) | ||
359 | bases[i].id = i; | ||
360 | |||
319 | host->syncpt = syncpt; | 361 | host->syncpt = syncpt; |
362 | host->bases = bases; | ||
320 | 363 | ||
321 | host1x_syncpt_restore(host); | 364 | host1x_syncpt_restore(host); |
322 | 365 | ||
323 | /* Allocate sync point to use for clearing waits for expired fences */ | 366 | /* Allocate sync point to use for clearing waits for expired fences */ |
324 | host->nop_sp = _host1x_syncpt_alloc(host, NULL, false); | 367 | host->nop_sp = host1x_syncpt_alloc(host, NULL, 0); |
325 | if (!host->nop_sp) | 368 | if (!host->nop_sp) |
326 | return -ENOMEM; | 369 | return -ENOMEM; |
327 | 370 | ||
@@ -329,10 +372,10 @@ int host1x_syncpt_init(struct host1x *host) | |||
329 | } | 372 | } |
330 | 373 | ||
331 | struct host1x_syncpt *host1x_syncpt_request(struct device *dev, | 374 | struct host1x_syncpt *host1x_syncpt_request(struct device *dev, |
332 | bool client_managed) | 375 | unsigned long flags) |
333 | { | 376 | { |
334 | struct host1x *host = dev_get_drvdata(dev->parent); | 377 | struct host1x *host = dev_get_drvdata(dev->parent); |
335 | return _host1x_syncpt_alloc(host, dev, client_managed); | 378 | return host1x_syncpt_alloc(host, dev, flags); |
336 | } | 379 | } |
337 | 380 | ||
338 | void host1x_syncpt_free(struct host1x_syncpt *sp) | 381 | void host1x_syncpt_free(struct host1x_syncpt *sp) |
@@ -340,7 +383,9 @@ void host1x_syncpt_free(struct host1x_syncpt *sp) | |||
340 | if (!sp) | 383 | if (!sp) |
341 | return; | 384 | return; |
342 | 385 | ||
386 | host1x_syncpt_base_free(sp->base); | ||
343 | kfree(sp->name); | 387 | kfree(sp->name); |
388 | sp->base = NULL; | ||
344 | sp->dev = NULL; | 389 | sp->dev = NULL; |
345 | sp->name = NULL; | 390 | sp->name = NULL; |
346 | sp->client_managed = false; | 391 | sp->client_managed = false; |
@@ -354,6 +399,25 @@ void host1x_syncpt_deinit(struct host1x *host) | |||
354 | kfree(sp->name); | 399 | kfree(sp->name); |
355 | } | 400 | } |
356 | 401 | ||
402 | /* | ||
403 | * Read max. It indicates how many operations there are in queue, either in | ||
404 | * channel or in a software thread. | ||
405 | * */ | ||
406 | u32 host1x_syncpt_read_max(struct host1x_syncpt *sp) | ||
407 | { | ||
408 | smp_rmb(); | ||
409 | return (u32)atomic_read(&sp->max_val); | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | * Read min, which is a shadow of the current sync point value in hardware. | ||
414 | */ | ||
415 | u32 host1x_syncpt_read_min(struct host1x_syncpt *sp) | ||
416 | { | ||
417 | smp_rmb(); | ||
418 | return (u32)atomic_read(&sp->min_val); | ||
419 | } | ||
420 | |||
357 | int host1x_syncpt_nb_pts(struct host1x *host) | 421 | int host1x_syncpt_nb_pts(struct host1x *host) |
358 | { | 422 | { |
359 | return host->info->nb_pts; | 423 | return host->info->nb_pts; |
@@ -375,3 +439,13 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id) | |||
375 | return NULL; | 439 | return NULL; |
376 | return host->syncpt + id; | 440 | return host->syncpt + id; |
377 | } | 441 | } |
442 | |||
443 | struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp) | ||
444 | { | ||
445 | return sp ? sp->base : NULL; | ||
446 | } | ||
447 | |||
448 | u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base) | ||
449 | { | ||
450 | return base->id; | ||
451 | } | ||
diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h index 267c0b9d3647..9056465ecd3f 100644 --- a/drivers/gpu/host1x/syncpt.h +++ b/drivers/gpu/host1x/syncpt.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #define __HOST1X_SYNCPT_H | 20 | #define __HOST1X_SYNCPT_H |
21 | 21 | ||
22 | #include <linux/atomic.h> | 22 | #include <linux/atomic.h> |
23 | #include <linux/host1x.h> | ||
23 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
24 | #include <linux/sched.h> | 25 | #include <linux/sched.h> |
25 | 26 | ||
@@ -30,6 +31,11 @@ struct host1x; | |||
30 | /* Reserved for replacing an expired wait with a NOP */ | 31 | /* Reserved for replacing an expired wait with a NOP */ |
31 | #define HOST1X_SYNCPT_RESERVED 0 | 32 | #define HOST1X_SYNCPT_RESERVED 0 |
32 | 33 | ||
34 | struct host1x_syncpt_base { | ||
35 | unsigned int id; | ||
36 | bool requested; | ||
37 | }; | ||
38 | |||
33 | struct host1x_syncpt { | 39 | struct host1x_syncpt { |
34 | int id; | 40 | int id; |
35 | atomic_t min_val; | 41 | atomic_t min_val; |
@@ -39,6 +45,7 @@ struct host1x_syncpt { | |||
39 | bool client_managed; | 45 | bool client_managed; |
40 | struct host1x *host; | 46 | struct host1x *host; |
41 | struct device *dev; | 47 | struct device *dev; |
48 | struct host1x_syncpt_base *base; | ||
42 | 49 | ||
43 | /* interrupt data */ | 50 | /* interrupt data */ |
44 | struct host1x_syncpt_intr intr; | 51 | struct host1x_syncpt_intr intr; |
@@ -50,25 +57,6 @@ int host1x_syncpt_init(struct host1x *host); | |||
50 | /* Free sync point array */ | 57 | /* Free sync point array */ |
51 | void host1x_syncpt_deinit(struct host1x *host); | 58 | void host1x_syncpt_deinit(struct host1x *host); |
52 | 59 | ||
53 | /* | ||
54 | * Read max. It indicates how many operations there are in queue, either in | ||
55 | * channel or in a software thread. | ||
56 | * */ | ||
57 | static inline u32 host1x_syncpt_read_max(struct host1x_syncpt *sp) | ||
58 | { | ||
59 | smp_rmb(); | ||
60 | return (u32)atomic_read(&sp->max_val); | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * Read min, which is a shadow of the current sync point value in hardware. | ||
65 | */ | ||
66 | static inline u32 host1x_syncpt_read_min(struct host1x_syncpt *sp) | ||
67 | { | ||
68 | smp_rmb(); | ||
69 | return (u32)atomic_read(&sp->min_val); | ||
70 | } | ||
71 | |||
72 | /* Return number of sync point supported. */ | 60 | /* Return number of sync point supported. */ |
73 | int host1x_syncpt_nb_pts(struct host1x *host); | 61 | int host1x_syncpt_nb_pts(struct host1x *host); |
74 | 62 | ||
@@ -112,9 +100,6 @@ static inline bool host1x_syncpt_idle(struct host1x_syncpt *sp) | |||
112 | return (min == max); | 100 | return (min == max); |
113 | } | 101 | } |
114 | 102 | ||
115 | /* Return pointer to struct denoting sync point id. */ | ||
116 | struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id); | ||
117 | |||
118 | /* Load current value from hardware to the shadow register. */ | 103 | /* Load current value from hardware to the shadow register. */ |
119 | u32 host1x_syncpt_load(struct host1x_syncpt *sp); | 104 | u32 host1x_syncpt_load(struct host1x_syncpt *sp); |
120 | 105 | ||
@@ -130,16 +115,9 @@ void host1x_syncpt_restore(struct host1x *host); | |||
130 | /* Read current wait base value into shadow register and return it. */ | 115 | /* Read current wait base value into shadow register and return it. */ |
131 | u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp); | 116 | u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp); |
132 | 117 | ||
133 | /* Request incrementing a sync point. */ | ||
134 | int host1x_syncpt_incr(struct host1x_syncpt *sp); | ||
135 | |||
136 | /* Indicate future operations by incrementing the sync point max. */ | 118 | /* Indicate future operations by incrementing the sync point max. */ |
137 | u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs); | 119 | u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs); |
138 | 120 | ||
139 | /* Wait until sync point reaches a threshold value, or a timeout. */ | ||
140 | int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, | ||
141 | long timeout, u32 *value); | ||
142 | |||
143 | /* Check if sync point id is valid. */ | 121 | /* Check if sync point id is valid. */ |
144 | static inline int host1x_syncpt_is_valid(struct host1x_syncpt *sp) | 122 | static inline int host1x_syncpt_is_valid(struct host1x_syncpt *sp) |
145 | { | 123 | { |
@@ -149,14 +127,4 @@ static inline int host1x_syncpt_is_valid(struct host1x_syncpt *sp) | |||
149 | /* Patch a wait by replacing it with a wait for syncpt 0 value 0 */ | 127 | /* Patch a wait by replacing it with a wait for syncpt 0 value 0 */ |
150 | int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr); | 128 | int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr); |
151 | 129 | ||
152 | /* Return id of the sync point */ | ||
153 | u32 host1x_syncpt_id(struct host1x_syncpt *sp); | ||
154 | |||
155 | /* Allocate a sync point for a device. */ | ||
156 | struct host1x_syncpt *host1x_syncpt_request(struct device *dev, | ||
157 | bool client_managed); | ||
158 | |||
159 | /* Free a sync point. */ | ||
160 | void host1x_syncpt_free(struct host1x_syncpt *sp); | ||
161 | |||
162 | #endif | 130 | #endif |