Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/nvidia/drm2/tegra_host1x.c
39483 views
1
/*-
2
* Copyright (c) 2015 Michal Meloun
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/param.h>
28
#include <sys/systm.h>
29
#include <sys/bus.h>
30
#include <sys/clock.h>
31
#include <sys/kernel.h>
32
#include <sys/limits.h>
33
#include <sys/lock.h>
34
35
#include <sys/module.h>
36
#include <sys/resource.h>
37
#include <sys/sx.h>
38
#include <sys/rman.h>
39
40
#include <machine/bus.h>
41
#include <machine/resource.h>
42
43
#include <dev/clk/clk.h>
44
#include <dev/hwreset/hwreset.h>
45
#include <dev/drm2/drmP.h>
46
#include <dev/drm2/drm_crtc_helper.h>
47
#include <dev/drm2/drm_fb_helper.h>
48
#include <dev/fdt/simplebus.h>
49
#include <dev/ofw/ofw_bus.h>
50
#include <dev/ofw/ofw_bus_subr.h>
51
52
#include <arm/nvidia/drm2/tegra_drm.h>
53
54
#include "fb_if.h"
55
#include "tegra_drm_if.h"
56
57
#define WR4(_sc, _r, _v) bus_rite_4((_sc)->mem_res, (_r), (_v))
58
#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
59
60
#define LOCK(_sc) sx_xlock(&(_sc)->lock)
61
#define UNLOCK(_sc) sx_xunlock(&(_sc)->lock)
62
#define SLEEP(_sc, timeout) sx_sleep(sc, &sc->lock, 0, "host1x", timeout);
63
#define LOCK_INIT(_sc) sx_init(&_sc->lock, "host1x")
64
#define LOCK_DESTROY(_sc) sx_destroy(&_sc->lock)
65
#define ASSERT_LOCKED(_sc) sx_assert(&_sc->lock, SA_LOCKED)
66
#define ASSERT_UNLOCKED(_sc) sx_assert(&_sc->lock, SA_UNLOCKED)
67
68
static struct ofw_compat_data compat_data[] = {
69
{"nvidia,tegra124-host1x", 1},
70
{NULL, 0}
71
};
72
73
#define DRIVER_NAME "tegra"
74
#define DRIVER_DESC "NVIDIA Tegra TK1"
75
#define DRIVER_DATE "20151101"
76
#define DRIVER_MAJOR 0
77
#define DRIVER_MINOR 0
78
#define DRIVER_PATCHLEVEL 0
79
80
struct client_info;
81
TAILQ_HEAD(client_list, client_info);
82
typedef struct client_list client_list_t;
83
84
struct client_info {
85
TAILQ_ENTRY(client_info) list_e;
86
device_t client;
87
int activated;
88
};
89
90
struct host1x_softc {
91
struct simplebus_softc simplebus_sc; /* must be first */
92
device_t dev;
93
struct sx lock;
94
int attach_done;
95
96
struct resource *mem_res;
97
struct resource *syncpt_irq_res;
98
void *syncpt_irq_h;
99
struct resource *gen_irq_res;
100
void *gen_irq_h;
101
102
clk_t clk;
103
hwreset_t reset;
104
struct intr_config_hook irq_hook;
105
106
int drm_inited;
107
client_list_t clients;
108
109
struct tegra_drm *tegra_drm;
110
};
111
112
static void
113
host1x_output_poll_changed(struct drm_device *drm_dev)
114
{
115
struct tegra_drm *drm;
116
117
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
118
if (drm->fb != NULL)
119
drm_fb_helper_hotplug_event(&drm->fb->fb_helper);
120
}
121
122
static const struct drm_mode_config_funcs mode_config_funcs = {
123
.fb_create = tegra_drm_fb_create,
124
.output_poll_changed = host1x_output_poll_changed,
125
};
126
127
static int
128
host1x_drm_init(struct host1x_softc *sc)
129
{
130
struct client_info *entry;
131
int rv;
132
133
LOCK(sc);
134
135
TAILQ_FOREACH(entry, &sc->clients, list_e) {
136
if (entry->activated)
137
continue;
138
rv = TEGRA_DRM_INIT_CLIENT(entry->client, sc->dev,
139
sc->tegra_drm);
140
if (rv != 0) {
141
device_printf(sc->dev,
142
"Cannot init DRM client %s: %d\n",
143
device_get_name(entry->client), rv);
144
return (rv);
145
}
146
entry->activated = 1;
147
}
148
UNLOCK(sc);
149
150
return (0);
151
}
152
153
static int
154
host1x_drm_exit(struct host1x_softc *sc)
155
{
156
struct client_info *entry;
157
int rv;
158
#ifdef FREEBSD_NOTYET
159
struct drm_device *dev, *tmp;
160
#endif
161
LOCK(sc);
162
if (!sc->drm_inited) {
163
UNLOCK(sc);
164
return (0);
165
}
166
TAILQ_FOREACH_REVERSE(entry, &sc->clients, client_list, list_e) {
167
if (!entry->activated)
168
continue;
169
rv = TEGRA_DRM_EXIT_CLIENT(entry->client, sc->dev,
170
sc->tegra_drm);
171
if (rv != 0) {
172
device_printf(sc->dev,
173
"Cannot exit DRM client %s: %d\n",
174
device_get_name(entry->client), rv);
175
}
176
entry->activated = 0;
177
}
178
179
#ifdef FREEBSD_NOTYET
180
list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
181
drm_put_dev(dev);
182
#endif
183
sc->drm_inited = 0;
184
UNLOCK(sc);
185
186
return (0);
187
}
188
189
static int
190
host1x_drm_load(struct drm_device *drm_dev, unsigned long flags)
191
{
192
struct host1x_softc *sc;
193
int rv;
194
195
sc = device_get_softc(drm_dev->dev);
196
197
drm_mode_config_init(drm_dev);
198
drm_dev->mode_config.min_width = 32;
199
drm_dev->mode_config.min_height = 32;
200
drm_dev->mode_config.max_width = 4096;
201
drm_dev->mode_config.max_height = 4096;
202
drm_dev->mode_config.funcs = &mode_config_funcs;
203
204
rv = host1x_drm_init(sc);
205
if (rv != 0)
206
goto fail_host1x;
207
208
drm_dev->irq_enabled = true;
209
drm_dev->max_vblank_count = 0xffffffff;
210
drm_dev->vblank_disable_allowed = true;
211
212
rv = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
213
if (rv != 0)
214
goto fail_vblank;
215
216
drm_mode_config_reset(drm_dev);
217
218
rv = tegra_drm_fb_init(drm_dev);
219
if (rv != 0)
220
goto fail_fb;
221
drm_kms_helper_poll_init(drm_dev);
222
223
return (0);
224
225
fail_fb:
226
tegra_drm_fb_destroy(drm_dev);
227
drm_vblank_cleanup(drm_dev);
228
fail_vblank:
229
host1x_drm_exit(sc);
230
fail_host1x:
231
drm_mode_config_cleanup(drm_dev);
232
233
return (rv);
234
}
235
236
static int
237
host1x_drm_unload(struct drm_device *drm_dev)
238
{
239
struct host1x_softc *sc;
240
int rv;
241
242
sc = device_get_softc(drm_dev->dev);
243
244
drm_kms_helper_poll_fini(drm_dev);
245
tegra_drm_fb_destroy(drm_dev);
246
drm_mode_config_cleanup(drm_dev);
247
248
rv = host1x_drm_exit(sc);
249
if (rv < 0)
250
return (rv);
251
return (0);
252
}
253
254
static int
255
host1x_drm_open(struct drm_device *drm_dev, struct drm_file *filp)
256
{
257
258
return (0);
259
}
260
261
static void
262
tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
263
{
264
struct drm_crtc *crtc;
265
266
list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
267
tegra_dc_cancel_page_flip(crtc, file);
268
}
269
270
static void
271
host1x_drm_lastclose(struct drm_device *drm_dev)
272
{
273
274
struct tegra_drm *drm;
275
276
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
277
if (drm->fb != NULL)
278
drm_fb_helper_restore_fbdev_mode(&drm->fb->fb_helper);
279
}
280
281
static int
282
host1x_drm_enable_vblank(struct drm_device *drm_dev, int pipe)
283
{
284
struct drm_crtc *crtc;
285
286
list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
287
if (pipe == tegra_dc_get_pipe(crtc)) {
288
tegra_dc_enable_vblank(crtc);
289
return (0);
290
}
291
}
292
return (-ENODEV);
293
}
294
295
static void
296
host1x_drm_disable_vblank(struct drm_device *drm_dev, int pipe)
297
{
298
struct drm_crtc *crtc;
299
300
list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
301
if (pipe == tegra_dc_get_pipe(crtc)) {
302
tegra_dc_disable_vblank(crtc);
303
return;
304
}
305
}
306
}
307
308
static struct drm_ioctl_desc host1x_drm_ioctls[] = {
309
};
310
311
struct drm_driver tegra_drm_driver = {
312
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
313
.load = host1x_drm_load,
314
.unload = host1x_drm_unload,
315
.open = host1x_drm_open,
316
.preclose = tegra_drm_preclose,
317
.lastclose = host1x_drm_lastclose,
318
319
.get_vblank_counter = drm_vblank_count,
320
.enable_vblank = host1x_drm_enable_vblank,
321
.disable_vblank = host1x_drm_disable_vblank,
322
323
/* Fields filled by tegra_bo_driver_register()
324
.gem_free_object
325
.gem_pager_ops
326
.dumb_create
327
.dumb_map_offset
328
.dumb_destroy
329
*/
330
.ioctls = host1x_drm_ioctls,
331
.num_ioctls = nitems(host1x_drm_ioctls),
332
333
.name = DRIVER_NAME,
334
.desc = DRIVER_DESC,
335
.date = DRIVER_DATE,
336
.major = DRIVER_MAJOR,
337
.minor = DRIVER_MINOR,
338
.patchlevel = DRIVER_PATCHLEVEL,
339
};
340
341
/*
342
* ----------------- Device methods -------------------------
343
*/
344
static void
345
host1x_irq_hook(void *arg)
346
{
347
struct host1x_softc *sc;
348
int rv;
349
350
sc = arg;
351
config_intrhook_disestablish(&sc->irq_hook);
352
353
tegra_bo_driver_register(&tegra_drm_driver);
354
rv = drm_get_platform_dev(sc->dev, &sc->tegra_drm->drm_dev,
355
&tegra_drm_driver);
356
if (rv != 0) {
357
device_printf(sc->dev, "drm_get_platform_dev(): %d\n", rv);
358
return;
359
}
360
361
sc->drm_inited = 1;
362
}
363
364
static struct fb_info *
365
host1x_fb_helper_getinfo(device_t dev)
366
{
367
struct host1x_softc *sc;
368
369
sc = device_get_softc(dev);
370
if (sc->tegra_drm == NULL)
371
return (NULL);
372
return (tegra_drm_fb_getinfo(&sc->tegra_drm->drm_dev));
373
}
374
375
static int
376
host1x_register_client(device_t dev, device_t client)
377
{
378
struct host1x_softc *sc;
379
struct client_info *entry;
380
381
sc = device_get_softc(dev);
382
383
entry = malloc(sizeof(struct client_info), M_DEVBUF, M_WAITOK | M_ZERO);
384
entry->client = client;
385
entry->activated = 0;
386
387
LOCK(sc);
388
TAILQ_INSERT_TAIL(&sc->clients, entry, list_e);
389
UNLOCK(sc);
390
391
return (0);
392
}
393
394
static int
395
host1x_deregister_client(device_t dev, device_t client)
396
{
397
struct host1x_softc *sc;
398
struct client_info *entry;
399
400
sc = device_get_softc(dev);
401
402
LOCK(sc);
403
TAILQ_FOREACH(entry, &sc->clients, list_e) {
404
if (entry->client == client) {
405
if (entry->activated)
406
panic("Tegra DRM: Attempt to deregister "
407
"activated client");
408
TAILQ_REMOVE(&sc->clients, entry, list_e);
409
free(entry, M_DEVBUF);
410
UNLOCK(sc);
411
return (0);
412
}
413
}
414
UNLOCK(sc);
415
416
return (0);
417
}
418
419
static void
420
host1x_gen_intr(void *arg)
421
{
422
struct host1x_softc *sc;
423
424
sc = (struct host1x_softc *)arg;
425
LOCK(sc);
426
UNLOCK(sc);
427
}
428
429
static void
430
host1x_syncpt_intr(void *arg)
431
{
432
struct host1x_softc *sc;
433
434
sc = (struct host1x_softc *)arg;
435
LOCK(sc);
436
UNLOCK(sc);
437
}
438
439
static void
440
host1x_new_pass(device_t dev)
441
{
442
struct host1x_softc *sc;
443
int rv, rid;
444
phandle_t node;
445
446
/*
447
* We attach during BUS_PASS_BUS (because we must overcome simplebus),
448
* but some of our FDT resources are not ready until BUS_PASS_DEFAULT
449
*/
450
sc = device_get_softc(dev);
451
if (sc->attach_done || bus_get_pass() < BUS_PASS_DEFAULT) {
452
bus_generic_new_pass(dev);
453
return;
454
}
455
456
sc->attach_done = 1;
457
node = ofw_bus_get_node(dev);
458
459
/* Allocate our IRQ resource. */
460
rid = 0;
461
sc->syncpt_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
462
RF_ACTIVE);
463
if (sc->syncpt_irq_res == NULL) {
464
device_printf(dev, "Cannot allocate interrupt.\n");
465
rv = ENXIO;
466
goto fail;
467
}
468
rid = 1;
469
sc->gen_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
470
RF_ACTIVE);
471
if (sc->gen_irq_res == NULL) {
472
device_printf(dev, "Cannot allocate interrupt.\n");
473
rv = ENXIO;
474
goto fail;
475
}
476
477
/* FDT resources */
478
rv = hwreset_get_by_ofw_name(sc->dev, 0, "host1x", &sc->reset);
479
if (rv != 0) {
480
device_printf(dev, "Cannot get fuse reset\n");
481
goto fail;
482
}
483
rv = clk_get_by_ofw_index(sc->dev, 0, 0, &sc->clk);
484
if (rv != 0) {
485
device_printf(dev, "Cannot get i2c clock: %d\n", rv);
486
goto fail;
487
}
488
489
rv = clk_enable(sc->clk);
490
if (rv != 0) {
491
device_printf(dev, "Cannot enable clock: %d\n", rv);
492
goto fail;
493
}
494
rv = hwreset_deassert(sc->reset);
495
if (rv != 0) {
496
device_printf(sc->dev, "Cannot clear reset\n");
497
goto fail;
498
}
499
500
/* Setup interrupts */
501
rv = bus_setup_intr(dev, sc->gen_irq_res,
502
INTR_TYPE_MISC | INTR_MPSAFE, NULL, host1x_gen_intr,
503
sc, &sc->gen_irq_h);
504
if (rv) {
505
device_printf(dev, "Cannot setup gen interrupt.\n");
506
goto fail;
507
}
508
509
rv = bus_setup_intr(dev, sc->syncpt_irq_res,
510
INTR_TYPE_MISC | INTR_MPSAFE, NULL, host1x_syncpt_intr,
511
sc, &sc->syncpt_irq_h);
512
if (rv) {
513
device_printf(dev, "Cannot setup syncpt interrupt.\n");
514
goto fail;
515
}
516
517
simplebus_init(dev, 0);
518
for (node = OF_child(node); node > 0; node = OF_peer(node))
519
simplebus_add_device(dev, node, 0, NULL, -1, NULL);
520
521
sc->irq_hook.ich_func = host1x_irq_hook;
522
sc->irq_hook.ich_arg = sc;
523
config_intrhook_establish(&sc->irq_hook);
524
bus_generic_new_pass(dev);
525
return;
526
527
fail:
528
device_detach(dev);
529
return;
530
}
531
532
static int
533
host1x_probe(device_t dev)
534
{
535
536
if (!ofw_bus_status_okay(dev))
537
return (ENXIO);
538
539
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
540
return (ENXIO);
541
542
return (BUS_PROBE_DEFAULT);
543
}
544
545
static int
546
host1x_attach(device_t dev)
547
{
548
int rv, rid;
549
struct host1x_softc *sc;
550
551
sc = device_get_softc(dev);
552
sc->tegra_drm = malloc(sizeof(struct tegra_drm), DRM_MEM_DRIVER,
553
M_WAITOK | M_ZERO);
554
555
/* crosslink together all worlds */
556
sc->dev = dev;
557
sc->tegra_drm->drm_dev.dev_private = &sc->tegra_drm;
558
sc->tegra_drm->drm_dev.dev = dev;
559
560
TAILQ_INIT(&sc->clients);
561
562
LOCK_INIT(sc);
563
564
/* Get the memory resource for the register mapping. */
565
rid = 0;
566
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
567
RF_ACTIVE);
568
if (sc->mem_res == NULL) {
569
device_printf(dev, "Cannot map registers.\n");
570
rv = ENXIO;
571
goto fail;
572
}
573
574
bus_attach_children(dev);
575
return (0);
576
577
fail:
578
if (sc->tegra_drm != NULL)
579
free(sc->tegra_drm, DRM_MEM_DRIVER);
580
if (sc->mem_res != NULL)
581
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
582
LOCK_DESTROY(sc);
583
return (rv);
584
}
585
586
static int
587
host1x_detach(device_t dev)
588
{
589
struct host1x_softc *sc;
590
int error;
591
592
error = bus_generic_detach(dev);
593
if (error != 0)
594
return (error);
595
596
sc = device_get_softc(dev);
597
598
host1x_drm_exit(sc);
599
600
if (sc->gen_irq_h != NULL)
601
bus_teardown_intr(dev, sc->gen_irq_res, sc->gen_irq_h);
602
if (sc->tegra_drm != NULL)
603
free(sc->tegra_drm, DRM_MEM_DRIVER);
604
if (sc->clk != NULL)
605
clk_release(sc->clk);
606
if (sc->reset != NULL)
607
hwreset_release(sc->reset);
608
if (sc->syncpt_irq_h != NULL)
609
bus_teardown_intr(dev, sc->syncpt_irq_res, sc->syncpt_irq_h);
610
if (sc->gen_irq_res != NULL)
611
bus_release_resource(dev, SYS_RES_IRQ, 1, sc->gen_irq_res);
612
if (sc->syncpt_irq_res != NULL)
613
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->syncpt_irq_res);
614
if (sc->mem_res != NULL)
615
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
616
LOCK_DESTROY(sc);
617
return (0);
618
}
619
620
static device_method_t host1x_methods[] = {
621
/* Device interface */
622
DEVMETHOD(device_probe, host1x_probe),
623
DEVMETHOD(device_attach, host1x_attach),
624
DEVMETHOD(device_detach, host1x_detach),
625
626
/* Bus interface */
627
DEVMETHOD(bus_new_pass, host1x_new_pass),
628
629
/* Framebuffer service methods */
630
DEVMETHOD(fb_getinfo, host1x_fb_helper_getinfo),
631
632
/* tegra drm interface */
633
DEVMETHOD(tegra_drm_register_client, host1x_register_client),
634
DEVMETHOD(tegra_drm_deregister_client, host1x_deregister_client),
635
636
DEVMETHOD_END
637
};
638
639
DEFINE_CLASS_1(host1x, host1x_driver, host1x_methods,
640
sizeof(struct host1x_softc), simplebus_driver);
641
EARLY_DRIVER_MODULE(host1x, simplebus, host1x_driver, 0, 0, BUS_PASS_BUS);
642
643
/* Bindings for fbd device. */
644
extern driver_t fbd_driver;
645
DRIVER_MODULE(fbd, host1x, fbd_driver, 0, 0);
646
647