Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/nvidia/drm2/tegra_dc.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/gpio.h>
31
#include <sys/kernel.h>
32
#include <sys/module.h>
33
#include <sys/malloc.h>
34
#include <sys/rman.h>
35
#include <sys/sysctl.h>
36
37
#include <machine/bus.h>
38
39
#include <dev/clk/clk.h>
40
#include <dev/hwreset/hwreset.h>
41
#include <dev/drm2/drmP.h>
42
#include <dev/drm2/drm_crtc_helper.h>
43
#include <dev/drm2/drm_fb_helper.h>
44
#include <dev/drm2/drm_fixed.h>
45
#include <dev/ofw/ofw_bus.h>
46
#include <dev/ofw/ofw_bus_subr.h>
47
48
#include <arm/nvidia/drm2/tegra_dc_reg.h>
49
#include <arm/nvidia/drm2/tegra_drm.h>
50
#include <arm/nvidia/tegra_pmc.h>
51
52
#include "tegra_drm_if.h"
53
#include "tegra_dc_if.h"
54
55
#define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, 4 * (_r), (_v))
56
#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, 4 * (_r))
57
58
#define LOCK(_sc) mtx_lock(&(_sc)->mtx)
59
#define UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
60
#define SLEEP(_sc, timeout) \
61
mtx_sleep(sc, &sc->mtx, 0, "tegra_dc_wait", timeout);
62
#define LOCK_INIT(_sc) \
63
mtx_init(&_sc->mtx, device_get_nameunit(_sc->dev), "tegra_dc", MTX_DEF)
64
#define LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx)
65
#define ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED)
66
#define ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED)
67
68
#define SYNCPT_VBLANK0 26
69
#define SYNCPT_VBLANK1 27
70
71
#define DC_MAX_PLANES 2 /* Maximum planes */
72
73
/* DRM Formats supported by DC */
74
/* XXXX expand me */
75
static uint32_t dc_plane_formats[] = {
76
DRM_FORMAT_XBGR8888,
77
DRM_FORMAT_XRGB8888,
78
DRM_FORMAT_RGB565,
79
DRM_FORMAT_UYVY,
80
DRM_FORMAT_YUYV,
81
DRM_FORMAT_YUV420,
82
DRM_FORMAT_YUV422,
83
};
84
85
/* Complete description of one window (plane) */
86
struct dc_window {
87
/* Source (in framebuffer) rectangle, in pixels */
88
u_int src_x;
89
u_int src_y;
90
u_int src_w;
91
u_int src_h;
92
93
/* Destination (on display) rectangle, in pixels */
94
u_int dst_x;
95
u_int dst_y;
96
u_int dst_w;
97
u_int dst_h;
98
99
/* Parsed pixel format */
100
u_int bits_per_pixel;
101
bool is_yuv; /* any YUV mode */
102
bool is_yuv_planar; /* planar YUV mode */
103
uint32_t color_mode; /* DC_WIN_COLOR_DEPTH */
104
uint32_t swap; /* DC_WIN_BYTE_SWAP */
105
uint32_t surface_kind; /* DC_WINBUF_SURFACE_KIND */
106
uint32_t block_height; /* DC_WINBUF_SURFACE_KIND */
107
108
/* Parsed flipping, rotation is not supported for pitched modes */
109
bool flip_x; /* inverted X-axis */
110
bool flip_y; /* inverted Y-axis */
111
bool transpose_xy; /* swap X and Y-axis */
112
113
/* Color planes base addresses and strides */
114
bus_size_t base[3];
115
uint32_t stride[3]; /* stride[2] isn't used by HW */
116
};
117
118
struct dc_softc {
119
device_t dev;
120
struct resource *mem_res;
121
struct resource *irq_res;
122
void *irq_ih;
123
struct mtx mtx;
124
125
clk_t clk_parent;
126
clk_t clk_dc;
127
hwreset_t hwreset_dc;
128
129
int pitch_align;
130
131
struct tegra_crtc tegra_crtc;
132
struct drm_pending_vblank_event *event;
133
struct drm_gem_object *cursor_gem;
134
};
135
136
static struct ofw_compat_data compat_data[] = {
137
{"nvidia,tegra124-dc", 1},
138
{NULL, 0},
139
};
140
141
/* Convert standard drm pixel format to tegra windows parameters. */
142
static int
143
dc_parse_drm_format(struct tegra_fb *fb, struct dc_window *win)
144
{
145
struct tegra_bo *bo;
146
uint32_t cm;
147
uint32_t sw;
148
bool is_yuv, is_yuv_planar;
149
int nplanes, i;
150
151
switch (fb->drm_fb.pixel_format) {
152
case DRM_FORMAT_XBGR8888:
153
sw = BYTE_SWAP(NOSWAP);
154
cm = WIN_COLOR_DEPTH_R8G8B8A8;
155
is_yuv = false;
156
is_yuv_planar = false;
157
break;
158
159
case DRM_FORMAT_XRGB8888:
160
sw = BYTE_SWAP(NOSWAP);
161
cm = WIN_COLOR_DEPTH_B8G8R8A8;
162
is_yuv = false;
163
is_yuv_planar = false;
164
break;
165
166
case DRM_FORMAT_RGB565:
167
sw = BYTE_SWAP(NOSWAP);
168
cm = WIN_COLOR_DEPTH_B5G6R5;
169
is_yuv = false;
170
is_yuv_planar = false;
171
break;
172
173
case DRM_FORMAT_UYVY:
174
sw = BYTE_SWAP(NOSWAP);
175
cm = WIN_COLOR_DEPTH_YCbCr422;
176
is_yuv = true;
177
is_yuv_planar = false;
178
break;
179
180
case DRM_FORMAT_YUYV:
181
sw = BYTE_SWAP(SWAP2);
182
cm = WIN_COLOR_DEPTH_YCbCr422;
183
is_yuv = true;
184
is_yuv_planar = false;
185
break;
186
187
case DRM_FORMAT_YUV420:
188
sw = BYTE_SWAP(NOSWAP);
189
cm = WIN_COLOR_DEPTH_YCbCr420P;
190
is_yuv = true;
191
is_yuv_planar = true;
192
break;
193
194
case DRM_FORMAT_YUV422:
195
sw = BYTE_SWAP(NOSWAP);
196
cm = WIN_COLOR_DEPTH_YCbCr422P;
197
is_yuv = true;
198
is_yuv_planar = true;
199
break;
200
201
default:
202
/* Unsupported format */
203
return (-EINVAL);
204
}
205
206
/* Basic check of arguments. */
207
switch (fb->rotation) {
208
case 0:
209
case 180:
210
break;
211
212
case 90: /* Rotation is supported only */
213
case 270: /* for block linear surfaces */
214
if (!fb->block_linear)
215
return (-EINVAL);
216
break;
217
218
default:
219
return (-EINVAL);
220
}
221
/* XXX Add more checks (sizes, scaling...) */
222
223
if (win == NULL)
224
return (0);
225
226
win->surface_kind =
227
fb->block_linear ? SURFACE_KIND_BL_16B2: SURFACE_KIND_PITCH;
228
win->block_height = fb->block_height;
229
switch (fb->rotation) {
230
case 0: /* (0,0,0) */
231
win->transpose_xy = false;
232
win->flip_x = false;
233
win->flip_y = false;
234
break;
235
236
case 90: /* (1,0,1) */
237
win->transpose_xy = true;
238
win->flip_x = false;
239
win->flip_y = true;
240
break;
241
242
case 180: /* (0,1,1) */
243
win->transpose_xy = false;
244
win->flip_x = true;
245
win->flip_y = true;
246
break;
247
248
case 270: /* (1,1,0) */
249
win->transpose_xy = true;
250
win->flip_x = true;
251
win->flip_y = false;
252
break;
253
}
254
win->flip_x ^= fb->flip_x;
255
win->flip_y ^= fb->flip_y;
256
257
win->color_mode = cm;
258
win->swap = sw;
259
win->bits_per_pixel = fb->drm_fb.bits_per_pixel;
260
win->is_yuv = is_yuv;
261
win->is_yuv_planar = is_yuv_planar;
262
263
nplanes = drm_format_num_planes(fb->drm_fb.pixel_format);
264
for (i = 0; i < nplanes; i++) {
265
bo = fb->planes[i];
266
win->base[i] = bo->pbase + fb->drm_fb.offsets[i];
267
win->stride[i] = fb->drm_fb.pitches[i];
268
}
269
return (0);
270
}
271
272
/*
273
* Scaling functions.
274
*
275
* It's unclear if we want/must program the fractional portion
276
* (aka bias) of init_dda registers, mainly when mirrored axis
277
* modes are used.
278
* For now, we use 1.0 as recommended by TRM.
279
*/
280
static inline uint32_t
281
dc_scaling_init(uint32_t start)
282
{
283
284
return (1 << 12);
285
}
286
287
static inline uint32_t
288
dc_scaling_incr(uint32_t src, uint32_t dst, uint32_t maxscale)
289
{
290
uint32_t val;
291
292
val = (src - 1) << 12 ; /* 4.12 fixed float */
293
val /= (dst - 1);
294
if (val > (maxscale << 12))
295
val = maxscale << 12;
296
return val;
297
}
298
299
/* -------------------------------------------------------------------
300
*
301
* HW Access.
302
*
303
*/
304
305
/*
306
* Setup pixel clock.
307
* Minimal frequency is pixel clock, but output is free to select
308
* any higher.
309
*/
310
static int
311
dc_setup_clk(struct dc_softc *sc, struct drm_crtc *crtc,
312
struct drm_display_mode *mode, uint32_t *div)
313
{
314
uint64_t pclk, freq;
315
struct tegra_drm_encoder *output;
316
struct drm_encoder *encoder;
317
long rv;
318
319
pclk = mode->clock * 1000;
320
321
/* Find attached encoder */
322
output = NULL;
323
list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list,
324
head) {
325
if (encoder->crtc == crtc) {
326
output = container_of(encoder, struct tegra_drm_encoder,
327
encoder);
328
break;
329
}
330
}
331
if (output == NULL)
332
return (-ENODEV);
333
334
if (output->setup_clock == NULL)
335
panic("Output have not setup_clock function.\n");
336
rv = output->setup_clock(output, sc->clk_dc, pclk);
337
if (rv != 0) {
338
device_printf(sc->dev, "Cannot setup pixel clock: %llu\n",
339
pclk);
340
return (rv);
341
}
342
343
rv = clk_get_freq(sc->clk_dc, &freq);
344
*div = (freq * 2 / pclk) - 2;
345
346
DRM_DEBUG_KMS("frequency: %llu, DC divider: %u\n", freq, *div);
347
348
return 0;
349
}
350
351
static void
352
dc_setup_window(struct dc_softc *sc, unsigned int index, struct dc_window *win)
353
{
354
uint32_t h_offset, v_offset, h_size, v_size, bpp;
355
uint32_t h_init_dda, v_init_dda, h_incr_dda, v_incr_dda;
356
uint32_t val;
357
358
#ifdef DMR_DEBUG_WINDOW
359
printf("%s window: %d\n", __func__, index);
360
printf(" src: x: %d, y: %d, w: %d, h: %d\n",
361
win->src_x, win->src_y, win->src_w, win->src_h);
362
printf(" dst: x: %d, y: %d, w: %d, h: %d\n",
363
win->dst_x, win->dst_y, win->dst_w, win->dst_h);
364
printf(" bpp: %d, color_mode: %d, swap: %d\n",
365
win->bits_per_pixel, win->color_mode, win->swap);
366
#endif
367
368
if (win->is_yuv)
369
bpp = win->is_yuv_planar ? 1 : 2;
370
else
371
bpp = (win->bits_per_pixel + 7) / 8;
372
373
if (!win->transpose_xy) {
374
h_size = win->src_w * bpp;
375
v_size = win->src_h;
376
} else {
377
h_size = win->src_h * bpp;
378
v_size = win->src_w;
379
}
380
381
h_offset = win->src_x * bpp;
382
v_offset = win->src_y;
383
if (win->flip_x) {
384
h_offset += win->src_w * bpp - 1;
385
}
386
if (win->flip_y)
387
v_offset += win->src_h - 1;
388
389
/* Adjust offsets for planar yuv modes */
390
if (win->is_yuv_planar) {
391
h_offset &= ~1;
392
if (win->flip_x )
393
h_offset |= 1;
394
v_offset &= ~1;
395
if (win->flip_y )
396
v_offset |= 1;
397
}
398
399
/* Setup scaling. */
400
if (!win->transpose_xy) {
401
h_init_dda = dc_scaling_init(win->src_x);
402
v_init_dda = dc_scaling_init(win->src_y);
403
h_incr_dda = dc_scaling_incr(win->src_w, win->dst_w, 4);
404
v_incr_dda = dc_scaling_incr(win->src_h, win->dst_h, 15);
405
} else {
406
h_init_dda = dc_scaling_init(win->src_y);
407
v_init_dda = dc_scaling_init(win->src_x);
408
h_incr_dda = dc_scaling_incr(win->src_h, win->dst_h, 4);
409
v_incr_dda = dc_scaling_incr(win->src_w, win->dst_w, 15);
410
}
411
#ifdef DMR_DEBUG_WINDOW
412
printf("\n");
413
printf(" bpp: %d, size: h: %d v: %d, offset: h:%d v: %d\n",
414
bpp, h_size, v_size, h_offset, v_offset);
415
printf(" init_dda: h: %d v: %d, incr_dda: h: %d v: %d\n",
416
h_init_dda, v_init_dda, h_incr_dda, v_incr_dda);
417
#endif
418
419
LOCK(sc);
420
421
/* Select target window */
422
val = WINDOW_A_SELECT << index;
423
WR4(sc, DC_CMD_DISPLAY_WINDOW_HEADER, val);
424
425
/* Sizes */
426
WR4(sc, DC_WIN_POSITION, WIN_POSITION(win->dst_x, win->dst_y));
427
WR4(sc, DC_WIN_SIZE, WIN_SIZE(win->dst_w, win->dst_h));
428
WR4(sc, DC_WIN_PRESCALED_SIZE, WIN_PRESCALED_SIZE(h_size, v_size));
429
430
/* DDA */
431
WR4(sc, DC_WIN_DDA_INCREMENT,
432
WIN_DDA_INCREMENT(h_incr_dda, v_incr_dda));
433
WR4(sc, DC_WIN_H_INITIAL_DDA, h_init_dda);
434
WR4(sc, DC_WIN_V_INITIAL_DDA, v_init_dda);
435
436
/* Color planes base addresses and strides */
437
WR4(sc, DC_WINBUF_START_ADDR, win->base[0]);
438
if (win->is_yuv_planar) {
439
WR4(sc, DC_WINBUF_START_ADDR_U, win->base[1]);
440
WR4(sc, DC_WINBUF_START_ADDR_V, win->base[2]);
441
WR4(sc, DC_WIN_LINE_STRIDE,
442
win->stride[1] << 16 | win->stride[0]);
443
} else {
444
WR4(sc, DC_WIN_LINE_STRIDE, win->stride[0]);
445
}
446
447
/* Offsets for rotation and axis flip */
448
WR4(sc, DC_WINBUF_ADDR_H_OFFSET, h_offset);
449
WR4(sc, DC_WINBUF_ADDR_V_OFFSET, v_offset);
450
451
/* Color format */
452
WR4(sc, DC_WIN_COLOR_DEPTH, win->color_mode);
453
WR4(sc, DC_WIN_BYTE_SWAP, win->swap);
454
455
/* Tiling */
456
val = win->surface_kind;
457
if (win->surface_kind == SURFACE_KIND_BL_16B2)
458
val |= SURFACE_KIND_BLOCK_HEIGHT(win->block_height);
459
WR4(sc, DC_WINBUF_SURFACE_KIND, val);
460
461
/* Color space coefs for YUV modes */
462
if (win->is_yuv) {
463
WR4(sc, DC_WINC_CSC_YOF, 0x00f0);
464
WR4(sc, DC_WINC_CSC_KYRGB, 0x012a);
465
WR4(sc, DC_WINC_CSC_KUR, 0x0000);
466
WR4(sc, DC_WINC_CSC_KVR, 0x0198);
467
WR4(sc, DC_WINC_CSC_KUG, 0x039b);
468
WR4(sc, DC_WINC_CSC_KVG, 0x032f);
469
WR4(sc, DC_WINC_CSC_KUB, 0x0204);
470
WR4(sc, DC_WINC_CSC_KVB, 0x0000);
471
}
472
473
val = WIN_ENABLE;
474
if (win->is_yuv)
475
val |= CSC_ENABLE;
476
else if (win->bits_per_pixel < 24)
477
val |= COLOR_EXPAND;
478
if (win->flip_y)
479
val |= V_DIRECTION;
480
if (win->flip_x)
481
val |= H_DIRECTION;
482
if (win->transpose_xy)
483
val |= SCAN_COLUMN;
484
WR4(sc, DC_WINC_WIN_OPTIONS, val);
485
486
#ifdef DMR_DEBUG_WINDOW
487
/* Set underflow debug mode -> highlight missing pixels. */
488
WR4(sc, DC_WINBUF_UFLOW_CTRL, UFLOW_CTR_ENABLE);
489
WR4(sc, DC_WINBUF_UFLOW_DBG_PIXEL, 0xFFFF0000);
490
#endif
491
492
UNLOCK(sc);
493
}
494
495
/* -------------------------------------------------------------------
496
*
497
* Plane functions.
498
*
499
*/
500
static int
501
dc_plane_update(struct drm_plane *drm_plane, struct drm_crtc *drm_crtc,
502
struct drm_framebuffer *drm_fb,
503
int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h,
504
uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h)
505
{
506
struct tegra_plane *plane;
507
struct tegra_crtc *crtc;
508
struct tegra_fb *fb;
509
struct dc_softc *sc;
510
struct dc_window win;
511
int rv;
512
513
plane = container_of(drm_plane, struct tegra_plane, drm_plane);
514
fb = container_of(drm_fb, struct tegra_fb, drm_fb);
515
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
516
sc = device_get_softc(crtc->dev);
517
518
memset(&win, 0, sizeof(win));
519
win.src_x = src_x >> 16;
520
win.src_y = src_y >> 16;
521
win.src_w = src_w >> 16;
522
win.src_h = src_h >> 16;
523
win.dst_x = crtc_x;
524
win.dst_y = crtc_y;
525
win.dst_w = crtc_w;
526
win.dst_h = crtc_h;
527
528
rv = dc_parse_drm_format(fb, &win);
529
if (rv != 0) {
530
DRM_WARNING("unsupported pixel format %d\n",
531
fb->drm_fb.pixel_format);
532
return (rv);
533
}
534
535
dc_setup_window(sc, plane->index, &win);
536
537
WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_UPDATE << plane->index);
538
WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_ACT_REQ << plane->index);
539
540
return (0);
541
}
542
543
static int
544
dc_plane_disable(struct drm_plane *drm_plane)
545
{
546
struct tegra_plane *plane;
547
struct tegra_crtc *crtc;
548
struct dc_softc *sc;
549
uint32_t val, idx;
550
551
if (drm_plane->crtc == NULL)
552
return (0);
553
plane = container_of(drm_plane, struct tegra_plane, drm_plane);
554
crtc = container_of(drm_plane->crtc, struct tegra_crtc, drm_crtc);
555
556
sc = device_get_softc(crtc->dev);
557
idx = plane->index;
558
559
LOCK(sc);
560
561
WR4(sc, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT << idx);
562
563
val = RD4(sc, DC_WINC_WIN_OPTIONS);
564
val &= ~WIN_ENABLE;
565
WR4(sc, DC_WINC_WIN_OPTIONS, val);
566
567
UNLOCK(sc);
568
569
WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_UPDATE << idx);
570
WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_ACT_REQ << idx);
571
572
return (0);
573
}
574
575
static void
576
dc_plane_destroy(struct drm_plane *plane)
577
{
578
579
dc_plane_disable(plane);
580
drm_plane_cleanup(plane);
581
free(plane, DRM_MEM_KMS);
582
}
583
584
static const struct drm_plane_funcs dc_plane_funcs = {
585
.update_plane = dc_plane_update,
586
.disable_plane = dc_plane_disable,
587
.destroy = dc_plane_destroy,
588
};
589
590
/* -------------------------------------------------------------------
591
*
592
* CRTC helper functions.
593
*
594
*/
595
static void
596
dc_crtc_dpms(struct drm_crtc *crtc, int mode)
597
{
598
/* Empty function */
599
}
600
601
static bool
602
dc_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
603
struct drm_display_mode *adjusted)
604
{
605
606
return (true);
607
}
608
609
static int
610
dc_set_base(struct dc_softc *sc, int x, int y, struct tegra_fb *fb)
611
{
612
struct dc_window win;
613
int rv;
614
615
memset(&win, 0, sizeof(win));
616
win.src_x = x;
617
win.src_y = y;
618
win.src_w = fb->drm_fb.width;
619
win.src_h = fb->drm_fb.height;
620
win.dst_x = x;
621
win.dst_y = y;
622
win.dst_w = fb->drm_fb.width;
623
win.dst_h = fb->drm_fb.height;
624
625
rv = dc_parse_drm_format(fb, &win);
626
if (rv != 0) {
627
DRM_WARNING("unsupported pixel format %d\n",
628
fb->drm_fb.pixel_format);
629
return (rv);
630
}
631
dc_setup_window(sc, 0, &win);
632
633
return (0);
634
}
635
636
static int
637
dc_crtc_mode_set(struct drm_crtc *drm_crtc, struct drm_display_mode *mode,
638
struct drm_display_mode *adjusted, int x, int y,
639
struct drm_framebuffer *old_fb)
640
{
641
struct dc_softc *sc;
642
struct tegra_crtc *crtc;
643
struct tegra_fb *fb;
644
struct dc_window win;
645
uint32_t div, h_ref_to_sync, v_ref_to_sync;
646
int rv;
647
648
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
649
sc = device_get_softc(crtc->dev);
650
fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb);
651
652
h_ref_to_sync = 1;
653
v_ref_to_sync = 1;
654
/* Setup timing */
655
rv = dc_setup_clk(sc, drm_crtc, mode, &div);
656
if (rv != 0) {
657
device_printf(sc->dev, "Cannot set pixel clock\n");
658
return (rv);
659
}
660
661
/* Timing */
662
WR4(sc, DC_DISP_DISP_TIMING_OPTIONS, 0);
663
664
WR4(sc, DC_DISP_REF_TO_SYNC,
665
(v_ref_to_sync << 16) |
666
h_ref_to_sync);
667
668
WR4(sc, DC_DISP_SYNC_WIDTH,
669
((mode->vsync_end - mode->vsync_start) << 16) |
670
((mode->hsync_end - mode->hsync_start) << 0));
671
672
WR4(sc, DC_DISP_BACK_PORCH,
673
((mode->vtotal - mode->vsync_end) << 16) |
674
((mode->htotal - mode->hsync_end) << 0));
675
676
WR4(sc, DC_DISP_FRONT_PORCH,
677
((mode->vsync_start - mode->vdisplay) << 16) |
678
((mode->hsync_start - mode->hdisplay) << 0));
679
680
WR4(sc, DC_DISP_DISP_ACTIVE,
681
(mode->vdisplay << 16) | mode->hdisplay);
682
683
WR4(sc, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT(DF1P1C));
684
685
WR4(sc,DC_DISP_DISP_CLOCK_CONTROL,
686
SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER(PCD1));
687
688
memset(&win, 0, sizeof(win));
689
win.src_x = x;
690
win.src_y = y;
691
win.src_w = mode->hdisplay;
692
win.src_h = mode->vdisplay;
693
win.dst_x = x;
694
win.dst_y = y;
695
win.dst_w = mode->hdisplay;
696
win.dst_h = mode->vdisplay;
697
698
rv = dc_parse_drm_format(fb, &win);
699
if (rv != 0) {
700
DRM_WARNING("unsupported pixel format %d\n",
701
drm_crtc->fb->pixel_format);
702
return (rv);
703
}
704
705
dc_setup_window(sc, 0, &win);
706
707
return (0);
708
709
}
710
711
static int
712
dc_crtc_mode_set_base(struct drm_crtc *drm_crtc, int x, int y,
713
struct drm_framebuffer *old_fb)
714
{
715
struct dc_softc *sc;
716
struct tegra_crtc *crtc;
717
struct tegra_fb *fb;
718
int rv;
719
720
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
721
fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb);
722
sc = device_get_softc(crtc->dev);
723
724
rv = dc_set_base(sc, x, y, fb);
725
726
/* Commit */
727
WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE);
728
WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ);
729
return (rv);
730
}
731
732
static void
733
dc_crtc_prepare(struct drm_crtc *drm_crtc)
734
{
735
736
struct dc_softc *sc;
737
struct tegra_crtc *crtc;
738
uint32_t val;
739
740
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
741
sc = device_get_softc(crtc->dev);
742
743
WR4(sc, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL);
744
/* XXX allocate syncpoint from host1x */
745
WR4(sc, DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE |
746
(sc->tegra_crtc.nvidia_head == 0 ? SYNCPT_VBLANK0: SYNCPT_VBLANK1));
747
748
WR4(sc, DC_CMD_DISPLAY_POWER_CONTROL,
749
PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
750
PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
751
752
val = RD4(sc, DC_CMD_DISPLAY_COMMAND);
753
val |= DISPLAY_CTRL_MODE(CTRL_MODE_C_DISPLAY);
754
WR4(sc, DC_CMD_DISPLAY_COMMAND, val);
755
756
WR4(sc, DC_CMD_INT_MASK,
757
WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
758
WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT);
759
760
WR4(sc, DC_CMD_INT_ENABLE,
761
VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
762
WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT);
763
}
764
765
static void
766
dc_crtc_commit(struct drm_crtc *drm_crtc)
767
{
768
struct dc_softc *sc;
769
struct tegra_crtc *crtc;
770
uint32_t val;
771
772
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
773
sc = device_get_softc(crtc->dev);
774
775
WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE);
776
777
val = RD4(sc, DC_CMD_INT_MASK);
778
val |= FRAME_END_INT;
779
WR4(sc, DC_CMD_INT_MASK, val);
780
781
val = RD4(sc, DC_CMD_INT_ENABLE);
782
val |= FRAME_END_INT;
783
WR4(sc, DC_CMD_INT_ENABLE, val);
784
785
WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ);
786
}
787
788
static void
789
dc_crtc_load_lut(struct drm_crtc *crtc)
790
{
791
792
/* empty function */
793
}
794
795
static const struct drm_crtc_helper_funcs dc_crtc_helper_funcs = {
796
.dpms = dc_crtc_dpms,
797
.mode_fixup = dc_crtc_mode_fixup,
798
.mode_set = dc_crtc_mode_set,
799
.mode_set_base = dc_crtc_mode_set_base,
800
.prepare = dc_crtc_prepare,
801
.commit = dc_crtc_commit,
802
.load_lut = dc_crtc_load_lut,
803
};
804
805
static int
806
drm_crtc_index(struct drm_crtc *crtc)
807
{
808
int idx;
809
struct drm_crtc *tmp;
810
811
idx = 0;
812
list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
813
if (tmp == crtc)
814
return (idx);
815
idx++;
816
}
817
panic("Cannot find CRTC");
818
}
819
820
/* -------------------------------------------------------------------
821
*
822
* Exported functions (mainly vsync related).
823
*
824
* XXX revisit this -> convert to bus methods?
825
*/
826
int
827
tegra_dc_get_pipe(struct drm_crtc *drm_crtc)
828
{
829
struct tegra_crtc *crtc;
830
831
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
832
return (crtc->nvidia_head);
833
}
834
835
void
836
tegra_dc_enable_vblank(struct drm_crtc *drm_crtc)
837
{
838
struct dc_softc *sc;
839
struct tegra_crtc *crtc;
840
uint32_t val;
841
842
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
843
sc = device_get_softc(crtc->dev);
844
845
LOCK(sc);
846
val = RD4(sc, DC_CMD_INT_MASK);
847
val |= VBLANK_INT;
848
WR4(sc, DC_CMD_INT_MASK, val);
849
UNLOCK(sc);
850
}
851
852
void
853
tegra_dc_disable_vblank(struct drm_crtc *drm_crtc)
854
{
855
struct dc_softc *sc;
856
struct tegra_crtc *crtc;
857
uint32_t val;
858
859
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
860
sc = device_get_softc(crtc->dev);
861
862
LOCK(sc);
863
val = RD4(sc, DC_CMD_INT_MASK);
864
val &= ~VBLANK_INT;
865
WR4(sc, DC_CMD_INT_MASK, val);
866
UNLOCK(sc);
867
}
868
869
static void
870
dc_finish_page_flip(struct dc_softc *sc)
871
{
872
struct drm_crtc *drm_crtc;
873
struct drm_device *drm;
874
struct tegra_fb *fb;
875
struct tegra_bo *bo;
876
uint32_t base;
877
int idx;
878
879
drm_crtc = &sc->tegra_crtc.drm_crtc;
880
drm = drm_crtc->dev;
881
fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb);
882
883
mtx_lock(&drm->event_lock);
884
885
if (sc->event == NULL) {
886
mtx_unlock(&drm->event_lock);
887
return;
888
}
889
890
LOCK(sc);
891
/* Read active copy of WINBUF_START_ADDR */
892
WR4(sc, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT);
893
WR4(sc, DC_CMD_STATE_ACCESS, READ_MUX);
894
base = RD4(sc, DC_WINBUF_START_ADDR);
895
WR4(sc, DC_CMD_STATE_ACCESS, 0);
896
UNLOCK(sc);
897
898
/* Is already active */
899
bo = tegra_fb_get_plane(fb, 0);
900
if (base == (bo->pbase + fb->drm_fb.offsets[0])) {
901
idx = drm_crtc_index(drm_crtc);
902
drm_send_vblank_event(drm, idx, sc->event);
903
drm_vblank_put(drm, idx);
904
sc->event = NULL;
905
}
906
907
mtx_unlock(&drm->event_lock);
908
}
909
910
void
911
tegra_dc_cancel_page_flip(struct drm_crtc *drm_crtc, struct drm_file *file)
912
{
913
struct dc_softc *sc;
914
struct tegra_crtc *crtc;
915
struct drm_device *drm;
916
917
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
918
sc = device_get_softc(crtc->dev);
919
drm = drm_crtc->dev;
920
mtx_lock(&drm->event_lock);
921
922
if ((sc->event != NULL) && (sc->event->base.file_priv == file)) {
923
sc->event->base.destroy(&sc->event->base);
924
drm_vblank_put(drm, drm_crtc_index(drm_crtc));
925
sc->event = NULL;
926
}
927
mtx_unlock(&drm->event_lock);
928
}
929
930
/* -------------------------------------------------------------------
931
*
932
* CRTC functions.
933
*
934
*/
935
static int
936
dc_page_flip(struct drm_crtc *drm_crtc, struct drm_framebuffer *drm_fb,
937
struct drm_pending_vblank_event *event)
938
{
939
struct dc_softc *sc;
940
struct tegra_crtc *crtc;
941
struct tegra_fb *fb;
942
struct drm_device *drm;
943
944
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
945
sc = device_get_softc(crtc->dev);
946
fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb);
947
drm = drm_crtc->dev;
948
949
if (sc->event != NULL)
950
return (-EBUSY);
951
952
if (event != NULL) {
953
event->pipe = sc->tegra_crtc.nvidia_head;
954
sc->event = event;
955
drm_vblank_get(drm, event->pipe);
956
}
957
958
dc_set_base(sc, drm_crtc->x, drm_crtc->y, fb);
959
drm_crtc->fb = drm_fb;
960
961
/* Commit */
962
WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE);
963
964
return (0);
965
}
966
967
static int
968
dc_cursor_set(struct drm_crtc *drm_crtc, struct drm_file *file,
969
uint32_t handle, uint32_t width, uint32_t height)
970
{
971
972
struct dc_softc *sc;
973
struct tegra_crtc *crtc;
974
struct drm_gem_object *gem;
975
struct tegra_bo *bo;
976
int i;
977
uint32_t val, *src, *dst;
978
979
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
980
sc = device_get_softc(crtc->dev);
981
982
if (width != height)
983
return (-EINVAL);
984
985
switch (width) {
986
case 32:
987
val = CURSOR_SIZE(C32x32);
988
break;
989
case 64:
990
val = CURSOR_SIZE(C64x64);
991
break;
992
case 128:
993
val = CURSOR_SIZE(C128x128);
994
break;
995
case 256:
996
val = CURSOR_SIZE(C256x256);
997
break;
998
default:
999
return (-EINVAL);
1000
}
1001
1002
bo = NULL;
1003
gem = NULL;
1004
if (handle != 0) {
1005
gem = drm_gem_object_lookup(drm_crtc->dev, file, handle);
1006
if (gem == NULL)
1007
return (-ENOENT);
1008
bo = container_of(gem, struct tegra_bo, gem_obj);
1009
}
1010
1011
if (sc->cursor_gem != NULL) {
1012
drm_gem_object_unreference(sc->cursor_gem);
1013
}
1014
sc->cursor_gem = gem;
1015
1016
if (bo != NULL) {
1017
/*
1018
* Copy cursor into cache and convert it from ARGB to RGBA.
1019
* XXXX - this is broken by design - client can write to BO at
1020
* any time. We can dedicate other window for cursor or switch
1021
* to sw cursor in worst case.
1022
*/
1023
src = (uint32_t *)bo->vbase;
1024
dst = (uint32_t *)crtc->cursor_vbase;
1025
for (i = 0; i < width * height; i++)
1026
dst[i] = (src[i] << 8) | (src[i] >> 24);
1027
1028
val |= CURSOR_CLIP(CC_DISPLAY);
1029
val |= CURSOR_START_ADDR(crtc->cursor_pbase);
1030
WR4(sc, DC_DISP_CURSOR_START_ADDR, val);
1031
1032
val = RD4(sc, DC_DISP_BLEND_CURSOR_CONTROL);
1033
val &= ~CURSOR_DST_BLEND_FACTOR_SELECT(~0);
1034
val &= ~CURSOR_SRC_BLEND_FACTOR_SELECT(~0);
1035
val |= CURSOR_MODE_SELECT;
1036
val |= CURSOR_DST_BLEND_FACTOR_SELECT(DST_NEG_K1_TIMES_SRC);
1037
val |= CURSOR_SRC_BLEND_FACTOR_SELECT(SRC_BLEND_K1_TIMES_SRC);
1038
val |= CURSOR_ALPHA(~0);
1039
WR4(sc, DC_DISP_BLEND_CURSOR_CONTROL, val);
1040
1041
val = RD4(sc, DC_DISP_DISP_WIN_OPTIONS);
1042
val |= CURSOR_ENABLE;
1043
WR4(sc, DC_DISP_DISP_WIN_OPTIONS, val);
1044
} else {
1045
val = RD4(sc, DC_DISP_DISP_WIN_OPTIONS);
1046
val &= ~CURSOR_ENABLE;
1047
WR4(sc, DC_DISP_DISP_WIN_OPTIONS, val);
1048
}
1049
1050
/* XXX This fixes cursor underflow issues, but why ? */
1051
WR4(sc, DC_DISP_CURSOR_UNDERFLOW_CTRL, CURSOR_UFLOW_CYA);
1052
1053
WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | CURSOR_UPDATE );
1054
WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | CURSOR_ACT_REQ);
1055
return (0);
1056
}
1057
1058
static int
1059
dc_cursor_move(struct drm_crtc *drm_crtc, int x, int y)
1060
{
1061
struct dc_softc *sc;
1062
struct tegra_crtc *crtc;
1063
1064
crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
1065
sc = device_get_softc(crtc->dev);
1066
WR4(sc, DC_DISP_CURSOR_POSITION, CURSOR_POSITION(x, y));
1067
1068
WR4(sc, DC_CMD_STATE_CONTROL, CURSOR_UPDATE);
1069
WR4(sc, DC_CMD_STATE_CONTROL, CURSOR_ACT_REQ);
1070
1071
return (0);
1072
}
1073
1074
static void
1075
dc_destroy(struct drm_crtc *crtc)
1076
{
1077
1078
drm_crtc_cleanup(crtc);
1079
memset(crtc, 0, sizeof(*crtc));
1080
}
1081
1082
static const struct drm_crtc_funcs dc_crtc_funcs = {
1083
.page_flip = dc_page_flip,
1084
.cursor_set = dc_cursor_set,
1085
.cursor_move = dc_cursor_move,
1086
.set_config = drm_crtc_helper_set_config,
1087
.destroy = dc_destroy,
1088
};
1089
1090
/* -------------------------------------------------------------------
1091
*
1092
* Bus and infrastructure.
1093
*
1094
*/
1095
static int
1096
dc_init_planes(struct dc_softc *sc, struct tegra_drm *drm)
1097
{
1098
int i, rv;
1099
struct tegra_plane *plane;
1100
1101
rv = 0;
1102
for (i = 0; i < DC_MAX_PLANES; i++) {
1103
plane = malloc(sizeof(*plane), DRM_MEM_KMS, M_WAITOK | M_ZERO);
1104
plane->index = i + 1;
1105
rv = drm_plane_init(&drm->drm_dev, &plane->drm_plane,
1106
1 << sc->tegra_crtc.nvidia_head, &dc_plane_funcs,
1107
dc_plane_formats, nitems(dc_plane_formats), false);
1108
if (rv != 0) {
1109
free(plane, DRM_MEM_KMS);
1110
return (rv);
1111
}
1112
}
1113
return 0;
1114
}
1115
1116
static void
1117
dc_display_enable(device_t dev, bool enable)
1118
{
1119
struct dc_softc *sc;
1120
uint32_t val;
1121
1122
sc = device_get_softc(dev);
1123
1124
/* Set display mode */
1125
val = enable ? CTRL_MODE_C_DISPLAY: CTRL_MODE_STOP;
1126
WR4(sc, DC_CMD_DISPLAY_COMMAND, DISPLAY_CTRL_MODE(val));
1127
1128
/* and commit it*/
1129
WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE);
1130
WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ);
1131
}
1132
1133
static void
1134
dc_hdmi_enable(device_t dev, bool enable)
1135
{
1136
struct dc_softc *sc;
1137
uint32_t val;
1138
1139
sc = device_get_softc(dev);
1140
1141
val = RD4(sc, DC_DISP_DISP_WIN_OPTIONS);
1142
if (enable)
1143
val |= HDMI_ENABLE;
1144
else
1145
val &= ~HDMI_ENABLE;
1146
WR4(sc, DC_DISP_DISP_WIN_OPTIONS, val);
1147
1148
}
1149
1150
static void
1151
dc_setup_timing(device_t dev, int h_pulse_start)
1152
{
1153
struct dc_softc *sc;
1154
1155
sc = device_get_softc(dev);
1156
1157
/* Setup display timing */
1158
WR4(sc, DC_DISP_DISP_TIMING_OPTIONS, VSYNC_H_POSITION(1));
1159
WR4(sc, DC_DISP_DISP_COLOR_CONTROL,
1160
DITHER_CONTROL(DITHER_DISABLE) | BASE_COLOR_SIZE(SIZE_BASE888));
1161
1162
WR4(sc, DC_DISP_DISP_SIGNAL_OPTIONS0, H_PULSE2_ENABLE);
1163
WR4(sc, DC_DISP_H_PULSE2_CONTROL,
1164
PULSE_CONTROL_QUAL(QUAL_VACTIVE) | PULSE_CONTROL_LAST(LAST_END_A));
1165
1166
WR4(sc, DC_DISP_H_PULSE2_POSITION_A,
1167
PULSE_START(h_pulse_start) | PULSE_END(h_pulse_start + 8));
1168
}
1169
1170
static void
1171
dc_intr(void *arg)
1172
{
1173
struct dc_softc *sc;
1174
uint32_t status;
1175
1176
sc = arg;
1177
1178
/* Confirm interrupt */
1179
status = RD4(sc, DC_CMD_INT_STATUS);
1180
WR4(sc, DC_CMD_INT_STATUS, status);
1181
if (status & VBLANK_INT) {
1182
drm_handle_vblank(sc->tegra_crtc.drm_crtc.dev,
1183
sc->tegra_crtc.nvidia_head);
1184
dc_finish_page_flip(sc);
1185
}
1186
}
1187
1188
static int
1189
dc_init_client(device_t dev, device_t host1x, struct tegra_drm *drm)
1190
{
1191
struct dc_softc *sc;
1192
int rv;
1193
1194
sc = device_get_softc(dev);
1195
1196
if (drm->pitch_align < sc->pitch_align)
1197
drm->pitch_align = sc->pitch_align;
1198
1199
drm_crtc_init(&drm->drm_dev, &sc->tegra_crtc.drm_crtc, &dc_crtc_funcs);
1200
drm_mode_crtc_set_gamma_size(&sc->tegra_crtc.drm_crtc, 256);
1201
drm_crtc_helper_add(&sc->tegra_crtc.drm_crtc, &dc_crtc_helper_funcs);
1202
1203
rv = dc_init_planes(sc, drm);
1204
if (rv!= 0){
1205
device_printf(dev, "Cannot init planes\n");
1206
return (rv);
1207
}
1208
1209
WR4(sc, DC_CMD_INT_TYPE,
1210
WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
1211
WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT);
1212
1213
WR4(sc, DC_CMD_INT_POLARITY,
1214
WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
1215
WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT);
1216
1217
WR4(sc, DC_CMD_INT_ENABLE, 0);
1218
WR4(sc, DC_CMD_INT_MASK, 0);
1219
1220
rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
1221
NULL, dc_intr, sc, &sc->irq_ih);
1222
if (rv != 0) {
1223
device_printf(dev, "Cannot register interrupt handler\n");
1224
return (rv);
1225
}
1226
1227
/* allocate memory for cursor cache */
1228
sc->tegra_crtc.cursor_vbase = kmem_alloc_contig(256 * 256 * 4,
1229
M_WAITOK | M_ZERO, 0, -1UL, PAGE_SIZE, 0,
1230
VM_MEMATTR_WRITE_COMBINING);
1231
sc->tegra_crtc.cursor_pbase =
1232
vtophys((uintptr_t)sc->tegra_crtc.cursor_vbase);
1233
return (0);
1234
}
1235
1236
static int
1237
dc_exit_client(device_t dev, device_t host1x, struct tegra_drm *drm)
1238
{
1239
struct dc_softc *sc;
1240
1241
sc = device_get_softc(dev);
1242
1243
if (sc->irq_ih != NULL)
1244
bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
1245
sc->irq_ih = NULL;
1246
1247
return (0);
1248
}
1249
1250
static int
1251
get_fdt_resources(struct dc_softc *sc, phandle_t node)
1252
{
1253
int rv;
1254
1255
rv = hwreset_get_by_ofw_name(sc->dev, 0, "dc", &sc->hwreset_dc);
1256
if (rv != 0) {
1257
device_printf(sc->dev, "Cannot get 'dc' reset\n");
1258
return (rv);
1259
}
1260
rv = clk_get_by_ofw_name(sc->dev, 0, "parent", &sc->clk_parent);
1261
if (rv != 0) {
1262
device_printf(sc->dev, "Cannot get 'parent' clock\n");
1263
return (rv);
1264
}
1265
rv = clk_get_by_ofw_name(sc->dev, 0, "dc", &sc->clk_dc);
1266
if (rv != 0) {
1267
device_printf(sc->dev, "Cannot get 'dc' clock\n");
1268
return (rv);
1269
}
1270
1271
rv = OF_getencprop(node, "nvidia,head", &sc->tegra_crtc.nvidia_head,
1272
sizeof(sc->tegra_crtc.nvidia_head));
1273
if (rv <= 0) {
1274
device_printf(sc->dev,
1275
"Cannot get 'nvidia,head' property\n");
1276
return (rv);
1277
}
1278
return (0);
1279
}
1280
1281
static int
1282
enable_fdt_resources(struct dc_softc *sc)
1283
{
1284
int id, rv;
1285
1286
rv = clk_set_parent_by_clk(sc->clk_dc, sc->clk_parent);
1287
if (rv != 0) {
1288
device_printf(sc->dev, "Cannot set parent for 'dc' clock\n");
1289
return (rv);
1290
}
1291
1292
id = (sc->tegra_crtc.nvidia_head == 0) ?
1293
TEGRA_POWERGATE_DIS: TEGRA_POWERGATE_DISB;
1294
rv = tegra_powergate_sequence_power_up(id, sc->clk_dc, sc->hwreset_dc);
1295
if (rv != 0) {
1296
device_printf(sc->dev, "Cannot enable 'DIS' powergate\n");
1297
return (rv);
1298
}
1299
1300
return (0);
1301
}
1302
1303
static int
1304
dc_probe(device_t dev)
1305
{
1306
1307
if (!ofw_bus_status_okay(dev))
1308
return (ENXIO);
1309
1310
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
1311
return (ENXIO);
1312
1313
device_set_desc(dev, "Tegra Display Controller");
1314
return (BUS_PROBE_DEFAULT);
1315
}
1316
1317
static int
1318
dc_attach(device_t dev)
1319
{
1320
struct dc_softc *sc;
1321
phandle_t node;
1322
int rid, rv;
1323
1324
sc = device_get_softc(dev);
1325
sc->dev = dev;
1326
sc->tegra_crtc.dev = dev;
1327
1328
node = ofw_bus_get_node(sc->dev);
1329
LOCK_INIT(sc);
1330
1331
rid = 0;
1332
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1333
RF_ACTIVE);
1334
if (sc->mem_res == NULL) {
1335
device_printf(dev, "Cannot allocate memory resources\n");
1336
goto fail;
1337
}
1338
1339
rid = 0;
1340
sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1341
if (sc->irq_res == NULL) {
1342
device_printf(dev, "Cannot allocate IRQ resources\n");
1343
goto fail;
1344
}
1345
1346
rv = get_fdt_resources(sc, node);
1347
if (rv != 0) {
1348
device_printf(dev, "Cannot parse FDT resources\n");
1349
goto fail;
1350
}
1351
rv = enable_fdt_resources(sc);
1352
if (rv != 0) {
1353
device_printf(dev, "Cannot enable FDT resources\n");
1354
goto fail;
1355
}
1356
1357
/*
1358
* Tegra124
1359
* - 64 for RGB modes
1360
* - 128 for YUV planar modes
1361
* - 256 for block linear modes
1362
*/
1363
sc->pitch_align = 256;
1364
1365
rv = TEGRA_DRM_REGISTER_CLIENT(device_get_parent(sc->dev), sc->dev);
1366
if (rv != 0) {
1367
device_printf(dev, "Cannot register DRM device\n");
1368
goto fail;
1369
}
1370
1371
bus_attach_children(dev);
1372
return (0);
1373
1374
fail:
1375
TEGRA_DRM_DEREGISTER_CLIENT(device_get_parent(sc->dev), sc->dev);
1376
if (sc->irq_ih != NULL)
1377
bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
1378
if (sc->clk_parent != NULL)
1379
clk_release(sc->clk_parent);
1380
if (sc->clk_dc != NULL)
1381
clk_release(sc->clk_dc);
1382
if (sc->hwreset_dc != NULL)
1383
hwreset_release(sc->hwreset_dc);
1384
if (sc->irq_res != NULL)
1385
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
1386
if (sc->mem_res != NULL)
1387
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
1388
LOCK_DESTROY(sc);
1389
1390
return (ENXIO);
1391
}
1392
1393
static int
1394
dc_detach(device_t dev)
1395
{
1396
struct dc_softc *sc;
1397
int error;
1398
1399
error = bus_generic_detach(dev);
1400
if (error != 0)
1401
return (error);
1402
1403
sc = device_get_softc(dev);
1404
1405
TEGRA_DRM_DEREGISTER_CLIENT(device_get_parent(sc->dev), sc->dev);
1406
1407
if (sc->irq_ih != NULL)
1408
bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
1409
if (sc->clk_parent != NULL)
1410
clk_release(sc->clk_parent);
1411
if (sc->clk_dc != NULL)
1412
clk_release(sc->clk_dc);
1413
if (sc->hwreset_dc != NULL)
1414
hwreset_release(sc->hwreset_dc);
1415
if (sc->irq_res != NULL)
1416
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
1417
if (sc->mem_res != NULL)
1418
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
1419
LOCK_DESTROY(sc);
1420
1421
return (0);
1422
}
1423
1424
static device_method_t tegra_dc_methods[] = {
1425
/* Device interface */
1426
DEVMETHOD(device_probe, dc_probe),
1427
DEVMETHOD(device_attach, dc_attach),
1428
DEVMETHOD(device_detach, dc_detach),
1429
1430
/* tegra drm interface */
1431
DEVMETHOD(tegra_drm_init_client, dc_init_client),
1432
DEVMETHOD(tegra_drm_exit_client, dc_exit_client),
1433
1434
/* tegra dc interface */
1435
DEVMETHOD(tegra_dc_display_enable, dc_display_enable),
1436
DEVMETHOD(tegra_dc_hdmi_enable, dc_hdmi_enable),
1437
DEVMETHOD(tegra_dc_setup_timing, dc_setup_timing),
1438
1439
DEVMETHOD_END
1440
};
1441
1442
DEFINE_CLASS_0(tegra_dc, tegra_dc_driver, tegra_dc_methods,
1443
sizeof(struct dc_softc));
1444
DRIVER_MODULE(tegra_dc, host1x, tegra_dc_driver, NULL, NULL);
1445
1446