diff options
-rw-r--r-- | Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 593 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 46 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dsi.c | 811 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dsi.h | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/fb.c | 52 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gem.c | 366 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gem.h | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/output.c | 35 | ||||
-rw-r--r-- | drivers/gpu/host1x/cdma.c | 2 | ||||
-rw-r--r-- | drivers/gpu/host1x/cdma.h | 2 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/cdma_hw.c | 10 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/channel_hw.c | 12 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/debug_hw.c | 4 | ||||
-rw-r--r-- | drivers/gpu/host1x/job.h | 2 | ||||
-rw-r--r-- | drivers/gpu/host1x/mipi.c | 148 | ||||
-rw-r--r-- | include/trace/events/host1x.h | 27 |
19 files changed, 1678 insertions, 481 deletions
diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index b48f4ef31d93..4c32ef0b7db8 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt | |||
@@ -191,6 +191,8 @@ of the following host1x client modules: | |||
191 | - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection | 191 | - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection |
192 | - nvidia,edid: supplies a binary EDID blob | 192 | - nvidia,edid: supplies a binary EDID blob |
193 | - nvidia,panel: phandle of a display panel | 193 | - nvidia,panel: phandle of a display panel |
194 | - nvidia,ganged-mode: contains a phandle to a second DSI controller to gang | ||
195 | up with in order to support up to 8 data lanes | ||
194 | 196 | ||
195 | - sor: serial output resource | 197 | - sor: serial output resource |
196 | 198 | ||
diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index 354ddb29231f..74d9d621453d 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config DRM_TEGRA | 1 | config DRM_TEGRA |
2 | tristate "NVIDIA Tegra DRM" | 2 | tristate "NVIDIA Tegra DRM" |
3 | depends on ARCH_TEGRA || (ARM && COMPILE_TEST) | 3 | depends on ARCH_TEGRA || (ARM && COMPILE_TEST) |
4 | depends on COMMON_CLK | ||
4 | depends on DRM | 5 | depends on DRM |
5 | depends on RESET_CONTROLLER | 6 | depends on RESET_CONTROLLER |
6 | select DRM_KMS_HELPER | 7 | select DRM_KMS_HELPER |
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index cdfa126a4725..b957908aec73 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
@@ -9,8 +9,11 @@ | |||
9 | 9 | ||
10 | #include <linux/clk.h> | 10 | #include <linux/clk.h> |
11 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
12 | #include <linux/iommu.h> | ||
12 | #include <linux/reset.h> | 13 | #include <linux/reset.h> |
13 | 14 | ||
15 | #include <soc/tegra/pmc.h> | ||
16 | |||
14 | #include "dc.h" | 17 | #include "dc.h" |
15 | #include "drm.h" | 18 | #include "drm.h" |
16 | #include "gem.h" | 19 | #include "gem.h" |
@@ -22,6 +25,7 @@ struct tegra_dc_soc_info { | |||
22 | bool supports_cursor; | 25 | bool supports_cursor; |
23 | bool supports_block_linear; | 26 | bool supports_block_linear; |
24 | unsigned int pitch_align; | 27 | unsigned int pitch_align; |
28 | bool has_powergate; | ||
25 | }; | 29 | }; |
26 | 30 | ||
27 | struct tegra_plane { | 31 | struct tegra_plane { |
@@ -34,6 +38,26 @@ static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane) | |||
34 | return container_of(plane, struct tegra_plane, base); | 38 | return container_of(plane, struct tegra_plane, base); |
35 | } | 39 | } |
36 | 40 | ||
41 | static void tegra_dc_window_commit(struct tegra_dc *dc, unsigned int index) | ||
42 | { | ||
43 | u32 value = WIN_A_ACT_REQ << index; | ||
44 | |||
45 | tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL); | ||
46 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
47 | } | ||
48 | |||
49 | static void tegra_dc_cursor_commit(struct tegra_dc *dc) | ||
50 | { | ||
51 | tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
52 | tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
53 | } | ||
54 | |||
55 | static void tegra_dc_commit(struct tegra_dc *dc) | ||
56 | { | ||
57 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
58 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
59 | } | ||
60 | |||
37 | static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap) | 61 | static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap) |
38 | { | 62 | { |
39 | /* assume no swapping of fetched data */ | 63 | /* assume no swapping of fetched data */ |
@@ -305,17 +329,260 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | |||
305 | break; | 329 | break; |
306 | } | 330 | } |
307 | 331 | ||
308 | tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL); | 332 | tegra_dc_window_commit(dc, index); |
309 | tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL); | 333 | |
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int tegra_window_plane_disable(struct drm_plane *plane) | ||
338 | { | ||
339 | struct tegra_dc *dc = to_tegra_dc(plane->crtc); | ||
340 | struct tegra_plane *p = to_tegra_plane(plane); | ||
341 | u32 value; | ||
342 | |||
343 | if (!plane->crtc) | ||
344 | return 0; | ||
345 | |||
346 | value = WINDOW_A_SELECT << p->index; | ||
347 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
348 | |||
349 | value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); | ||
350 | value &= ~WIN_ENABLE; | ||
351 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
352 | |||
353 | tegra_dc_window_commit(dc, p->index); | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static void tegra_plane_destroy(struct drm_plane *plane) | ||
359 | { | ||
360 | struct tegra_plane *p = to_tegra_plane(plane); | ||
361 | |||
362 | drm_plane_cleanup(plane); | ||
363 | kfree(p); | ||
364 | } | ||
365 | |||
366 | static const u32 tegra_primary_plane_formats[] = { | ||
367 | DRM_FORMAT_XBGR8888, | ||
368 | DRM_FORMAT_XRGB8888, | ||
369 | DRM_FORMAT_RGB565, | ||
370 | }; | ||
371 | |||
372 | static int tegra_primary_plane_update(struct drm_plane *plane, | ||
373 | struct drm_crtc *crtc, | ||
374 | struct drm_framebuffer *fb, int crtc_x, | ||
375 | int crtc_y, unsigned int crtc_w, | ||
376 | unsigned int crtc_h, uint32_t src_x, | ||
377 | uint32_t src_y, uint32_t src_w, | ||
378 | uint32_t src_h) | ||
379 | { | ||
380 | struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); | ||
381 | struct tegra_plane *p = to_tegra_plane(plane); | ||
382 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
383 | struct tegra_dc_window window; | ||
384 | int err; | ||
385 | |||
386 | memset(&window, 0, sizeof(window)); | ||
387 | window.src.x = src_x >> 16; | ||
388 | window.src.y = src_y >> 16; | ||
389 | window.src.w = src_w >> 16; | ||
390 | window.src.h = src_h >> 16; | ||
391 | window.dst.x = crtc_x; | ||
392 | window.dst.y = crtc_y; | ||
393 | window.dst.w = crtc_w; | ||
394 | window.dst.h = crtc_h; | ||
395 | window.format = tegra_dc_format(fb->pixel_format, &window.swap); | ||
396 | window.bits_per_pixel = fb->bits_per_pixel; | ||
397 | window.bottom_up = tegra_fb_is_bottom_up(fb); | ||
398 | |||
399 | err = tegra_fb_get_tiling(fb, &window.tiling); | ||
400 | if (err < 0) | ||
401 | return err; | ||
402 | |||
403 | window.base[0] = bo->paddr + fb->offsets[0]; | ||
404 | window.stride[0] = fb->pitches[0]; | ||
405 | |||
406 | err = tegra_dc_setup_window(dc, p->index, &window); | ||
407 | if (err < 0) | ||
408 | return err; | ||
310 | 409 | ||
311 | return 0; | 410 | return 0; |
312 | } | 411 | } |
313 | 412 | ||
314 | static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | 413 | static void tegra_primary_plane_destroy(struct drm_plane *plane) |
315 | struct drm_framebuffer *fb, int crtc_x, | 414 | { |
316 | int crtc_y, unsigned int crtc_w, | 415 | tegra_window_plane_disable(plane); |
317 | unsigned int crtc_h, uint32_t src_x, | 416 | tegra_plane_destroy(plane); |
318 | uint32_t src_y, uint32_t src_w, uint32_t src_h) | 417 | } |
418 | |||
419 | static const struct drm_plane_funcs tegra_primary_plane_funcs = { | ||
420 | .update_plane = tegra_primary_plane_update, | ||
421 | .disable_plane = tegra_window_plane_disable, | ||
422 | .destroy = tegra_primary_plane_destroy, | ||
423 | }; | ||
424 | |||
425 | static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm, | ||
426 | struct tegra_dc *dc) | ||
427 | { | ||
428 | struct tegra_plane *plane; | ||
429 | unsigned int num_formats; | ||
430 | const u32 *formats; | ||
431 | int err; | ||
432 | |||
433 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); | ||
434 | if (!plane) | ||
435 | return ERR_PTR(-ENOMEM); | ||
436 | |||
437 | num_formats = ARRAY_SIZE(tegra_primary_plane_formats); | ||
438 | formats = tegra_primary_plane_formats; | ||
439 | |||
440 | err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe, | ||
441 | &tegra_primary_plane_funcs, formats, | ||
442 | num_formats, DRM_PLANE_TYPE_PRIMARY); | ||
443 | if (err < 0) { | ||
444 | kfree(plane); | ||
445 | return ERR_PTR(err); | ||
446 | } | ||
447 | |||
448 | return &plane->base; | ||
449 | } | ||
450 | |||
451 | static const u32 tegra_cursor_plane_formats[] = { | ||
452 | DRM_FORMAT_RGBA8888, | ||
453 | }; | ||
454 | |||
455 | static int tegra_cursor_plane_update(struct drm_plane *plane, | ||
456 | struct drm_crtc *crtc, | ||
457 | struct drm_framebuffer *fb, int crtc_x, | ||
458 | int crtc_y, unsigned int crtc_w, | ||
459 | unsigned int crtc_h, uint32_t src_x, | ||
460 | uint32_t src_y, uint32_t src_w, | ||
461 | uint32_t src_h) | ||
462 | { | ||
463 | struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); | ||
464 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
465 | u32 value = CURSOR_CLIP_DISPLAY; | ||
466 | |||
467 | /* scaling not supported for cursor */ | ||
468 | if ((src_w >> 16 != crtc_w) || (src_h >> 16 != crtc_h)) | ||
469 | return -EINVAL; | ||
470 | |||
471 | /* only square cursors supported */ | ||
472 | if (src_w != src_h) | ||
473 | return -EINVAL; | ||
474 | |||
475 | switch (crtc_w) { | ||
476 | case 32: | ||
477 | value |= CURSOR_SIZE_32x32; | ||
478 | break; | ||
479 | |||
480 | case 64: | ||
481 | value |= CURSOR_SIZE_64x64; | ||
482 | break; | ||
483 | |||
484 | case 128: | ||
485 | value |= CURSOR_SIZE_128x128; | ||
486 | break; | ||
487 | |||
488 | case 256: | ||
489 | value |= CURSOR_SIZE_256x256; | ||
490 | break; | ||
491 | |||
492 | default: | ||
493 | return -EINVAL; | ||
494 | } | ||
495 | |||
496 | value |= (bo->paddr >> 10) & 0x3fffff; | ||
497 | tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR); | ||
498 | |||
499 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT | ||
500 | value = (bo->paddr >> 32) & 0x3; | ||
501 | tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI); | ||
502 | #endif | ||
503 | |||
504 | /* enable cursor and set blend mode */ | ||
505 | value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); | ||
506 | value |= CURSOR_ENABLE; | ||
507 | tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); | ||
508 | |||
509 | value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL); | ||
510 | value &= ~CURSOR_DST_BLEND_MASK; | ||
511 | value &= ~CURSOR_SRC_BLEND_MASK; | ||
512 | value |= CURSOR_MODE_NORMAL; | ||
513 | value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC; | ||
514 | value |= CURSOR_SRC_BLEND_K1_TIMES_SRC; | ||
515 | value |= CURSOR_ALPHA; | ||
516 | tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL); | ||
517 | |||
518 | /* position the cursor */ | ||
519 | value = (crtc_y & 0x3fff) << 16 | (crtc_x & 0x3fff); | ||
520 | tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION); | ||
521 | |||
522 | /* apply changes */ | ||
523 | tegra_dc_cursor_commit(dc); | ||
524 | tegra_dc_commit(dc); | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | static int tegra_cursor_plane_disable(struct drm_plane *plane) | ||
530 | { | ||
531 | struct tegra_dc *dc = to_tegra_dc(plane->crtc); | ||
532 | u32 value; | ||
533 | |||
534 | if (!plane->crtc) | ||
535 | return 0; | ||
536 | |||
537 | value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); | ||
538 | value &= ~CURSOR_ENABLE; | ||
539 | tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); | ||
540 | |||
541 | tegra_dc_cursor_commit(dc); | ||
542 | tegra_dc_commit(dc); | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static const struct drm_plane_funcs tegra_cursor_plane_funcs = { | ||
548 | .update_plane = tegra_cursor_plane_update, | ||
549 | .disable_plane = tegra_cursor_plane_disable, | ||
550 | .destroy = tegra_plane_destroy, | ||
551 | }; | ||
552 | |||
553 | static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm, | ||
554 | struct tegra_dc *dc) | ||
555 | { | ||
556 | struct tegra_plane *plane; | ||
557 | unsigned int num_formats; | ||
558 | const u32 *formats; | ||
559 | int err; | ||
560 | |||
561 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); | ||
562 | if (!plane) | ||
563 | return ERR_PTR(-ENOMEM); | ||
564 | |||
565 | num_formats = ARRAY_SIZE(tegra_cursor_plane_formats); | ||
566 | formats = tegra_cursor_plane_formats; | ||
567 | |||
568 | err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe, | ||
569 | &tegra_cursor_plane_funcs, formats, | ||
570 | num_formats, DRM_PLANE_TYPE_CURSOR); | ||
571 | if (err < 0) { | ||
572 | kfree(plane); | ||
573 | return ERR_PTR(err); | ||
574 | } | ||
575 | |||
576 | return &plane->base; | ||
577 | } | ||
578 | |||
579 | static int tegra_overlay_plane_update(struct drm_plane *plane, | ||
580 | struct drm_crtc *crtc, | ||
581 | struct drm_framebuffer *fb, int crtc_x, | ||
582 | int crtc_y, unsigned int crtc_w, | ||
583 | unsigned int crtc_h, uint32_t src_x, | ||
584 | uint32_t src_y, uint32_t src_w, | ||
585 | uint32_t src_h) | ||
319 | { | 586 | { |
320 | struct tegra_plane *p = to_tegra_plane(plane); | 587 | struct tegra_plane *p = to_tegra_plane(plane); |
321 | struct tegra_dc *dc = to_tegra_dc(crtc); | 588 | struct tegra_dc *dc = to_tegra_dc(crtc); |
@@ -361,44 +628,19 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | |||
361 | return tegra_dc_setup_window(dc, p->index, &window); | 628 | return tegra_dc_setup_window(dc, p->index, &window); |
362 | } | 629 | } |
363 | 630 | ||
364 | static int tegra_plane_disable(struct drm_plane *plane) | 631 | static void tegra_overlay_plane_destroy(struct drm_plane *plane) |
365 | { | 632 | { |
366 | struct tegra_dc *dc = to_tegra_dc(plane->crtc); | 633 | tegra_window_plane_disable(plane); |
367 | struct tegra_plane *p = to_tegra_plane(plane); | 634 | tegra_plane_destroy(plane); |
368 | unsigned long value; | ||
369 | |||
370 | if (!plane->crtc) | ||
371 | return 0; | ||
372 | |||
373 | value = WINDOW_A_SELECT << p->index; | ||
374 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
375 | |||
376 | value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); | ||
377 | value &= ~WIN_ENABLE; | ||
378 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
379 | |||
380 | tegra_dc_writel(dc, WIN_A_UPDATE << p->index, DC_CMD_STATE_CONTROL); | ||
381 | tegra_dc_writel(dc, WIN_A_ACT_REQ << p->index, DC_CMD_STATE_CONTROL); | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static void tegra_plane_destroy(struct drm_plane *plane) | ||
387 | { | ||
388 | struct tegra_plane *p = to_tegra_plane(plane); | ||
389 | |||
390 | tegra_plane_disable(plane); | ||
391 | drm_plane_cleanup(plane); | ||
392 | kfree(p); | ||
393 | } | 635 | } |
394 | 636 | ||
395 | static const struct drm_plane_funcs tegra_plane_funcs = { | 637 | static const struct drm_plane_funcs tegra_overlay_plane_funcs = { |
396 | .update_plane = tegra_plane_update, | 638 | .update_plane = tegra_overlay_plane_update, |
397 | .disable_plane = tegra_plane_disable, | 639 | .disable_plane = tegra_window_plane_disable, |
398 | .destroy = tegra_plane_destroy, | 640 | .destroy = tegra_overlay_plane_destroy, |
399 | }; | 641 | }; |
400 | 642 | ||
401 | static const uint32_t plane_formats[] = { | 643 | static const uint32_t tegra_overlay_plane_formats[] = { |
402 | DRM_FORMAT_XBGR8888, | 644 | DRM_FORMAT_XBGR8888, |
403 | DRM_FORMAT_XRGB8888, | 645 | DRM_FORMAT_XRGB8888, |
404 | DRM_FORMAT_RGB565, | 646 | DRM_FORMAT_RGB565, |
@@ -408,27 +650,44 @@ static const uint32_t plane_formats[] = { | |||
408 | DRM_FORMAT_YUV422, | 650 | DRM_FORMAT_YUV422, |
409 | }; | 651 | }; |
410 | 652 | ||
411 | static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) | 653 | static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, |
654 | struct tegra_dc *dc, | ||
655 | unsigned int index) | ||
412 | { | 656 | { |
413 | unsigned int i; | 657 | struct tegra_plane *plane; |
414 | int err = 0; | 658 | unsigned int num_formats; |
659 | const u32 *formats; | ||
660 | int err; | ||
415 | 661 | ||
416 | for (i = 0; i < 2; i++) { | 662 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); |
417 | struct tegra_plane *plane; | 663 | if (!plane) |
664 | return ERR_PTR(-ENOMEM); | ||
418 | 665 | ||
419 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); | 666 | plane->index = index; |
420 | if (!plane) | ||
421 | return -ENOMEM; | ||
422 | 667 | ||
423 | plane->index = 1 + i; | 668 | num_formats = ARRAY_SIZE(tegra_overlay_plane_formats); |
669 | formats = tegra_overlay_plane_formats; | ||
424 | 670 | ||
425 | err = drm_plane_init(drm, &plane->base, 1 << dc->pipe, | 671 | err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe, |
426 | &tegra_plane_funcs, plane_formats, | 672 | &tegra_overlay_plane_funcs, formats, |
427 | ARRAY_SIZE(plane_formats), false); | 673 | num_formats, DRM_PLANE_TYPE_OVERLAY); |
428 | if (err < 0) { | 674 | if (err < 0) { |
429 | kfree(plane); | 675 | kfree(plane); |
430 | return err; | 676 | return ERR_PTR(err); |
431 | } | 677 | } |
678 | |||
679 | return &plane->base; | ||
680 | } | ||
681 | |||
682 | static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) | ||
683 | { | ||
684 | struct drm_plane *plane; | ||
685 | unsigned int i; | ||
686 | |||
687 | for (i = 0; i < 2; i++) { | ||
688 | plane = tegra_dc_overlay_plane_create(drm, dc, 1 + i); | ||
689 | if (IS_ERR(plane)) | ||
690 | return PTR_ERR(plane); | ||
432 | } | 691 | } |
433 | 692 | ||
434 | return 0; | 693 | return 0; |
@@ -515,10 +774,8 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, | |||
515 | tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); | 774 | tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); |
516 | tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); | 775 | tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); |
517 | 776 | ||
518 | value = GENERAL_UPDATE | WIN_A_UPDATE; | ||
519 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
520 | |||
521 | value = GENERAL_ACT_REQ | WIN_A_ACT_REQ; | 777 | value = GENERAL_ACT_REQ | WIN_A_ACT_REQ; |
778 | tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL); | ||
522 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | 779 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); |
523 | 780 | ||
524 | return 0; | 781 | return 0; |
@@ -550,109 +807,6 @@ void tegra_dc_disable_vblank(struct tegra_dc *dc) | |||
550 | spin_unlock_irqrestore(&dc->lock, flags); | 807 | spin_unlock_irqrestore(&dc->lock, flags); |
551 | } | 808 | } |
552 | 809 | ||
553 | static int tegra_dc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file, | ||
554 | uint32_t handle, uint32_t width, | ||
555 | uint32_t height, int32_t hot_x, int32_t hot_y) | ||
556 | { | ||
557 | unsigned long value = CURSOR_CLIP_DISPLAY; | ||
558 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
559 | struct drm_gem_object *gem; | ||
560 | struct tegra_bo *bo = NULL; | ||
561 | |||
562 | if (!dc->soc->supports_cursor) | ||
563 | return -ENXIO; | ||
564 | |||
565 | if (width != height) | ||
566 | return -EINVAL; | ||
567 | |||
568 | switch (width) { | ||
569 | case 32: | ||
570 | value |= CURSOR_SIZE_32x32; | ||
571 | break; | ||
572 | |||
573 | case 64: | ||
574 | value |= CURSOR_SIZE_64x64; | ||
575 | break; | ||
576 | |||
577 | case 128: | ||
578 | value |= CURSOR_SIZE_128x128; | ||
579 | |||
580 | case 256: | ||
581 | value |= CURSOR_SIZE_256x256; | ||
582 | break; | ||
583 | |||
584 | default: | ||
585 | return -EINVAL; | ||
586 | } | ||
587 | |||
588 | if (handle) { | ||
589 | gem = drm_gem_object_lookup(crtc->dev, file, handle); | ||
590 | if (!gem) | ||
591 | return -ENOENT; | ||
592 | |||
593 | bo = to_tegra_bo(gem); | ||
594 | } | ||
595 | |||
596 | if (bo) { | ||
597 | unsigned long addr = (bo->paddr & 0xfffffc00) >> 10; | ||
598 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT | ||
599 | unsigned long high = (bo->paddr & 0xfffffffc) >> 32; | ||
600 | #endif | ||
601 | |||
602 | tegra_dc_writel(dc, value | addr, DC_DISP_CURSOR_START_ADDR); | ||
603 | |||
604 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT | ||
605 | tegra_dc_writel(dc, high, DC_DISP_CURSOR_START_ADDR_HI); | ||
606 | #endif | ||
607 | |||
608 | value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); | ||
609 | value |= CURSOR_ENABLE; | ||
610 | tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); | ||
611 | |||
612 | value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL); | ||
613 | value &= ~CURSOR_DST_BLEND_MASK; | ||
614 | value &= ~CURSOR_SRC_BLEND_MASK; | ||
615 | value |= CURSOR_MODE_NORMAL; | ||
616 | value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC; | ||
617 | value |= CURSOR_SRC_BLEND_K1_TIMES_SRC; | ||
618 | value |= CURSOR_ALPHA; | ||
619 | tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL); | ||
620 | } else { | ||
621 | value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); | ||
622 | value &= ~CURSOR_ENABLE; | ||
623 | tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); | ||
624 | } | ||
625 | |||
626 | tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
627 | tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
628 | |||
629 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
630 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
631 | |||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | static int tegra_dc_cursor_move(struct drm_crtc *crtc, int x, int y) | ||
636 | { | ||
637 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
638 | unsigned long value; | ||
639 | |||
640 | if (!dc->soc->supports_cursor) | ||
641 | return -ENXIO; | ||
642 | |||
643 | value = ((y & 0x3fff) << 16) | (x & 0x3fff); | ||
644 | tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION); | ||
645 | |||
646 | tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
647 | tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
648 | |||
649 | /* XXX: only required on generations earlier than Tegra124? */ | ||
650 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
651 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
652 | |||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | static void tegra_dc_finish_page_flip(struct tegra_dc *dc) | 810 | static void tegra_dc_finish_page_flip(struct tegra_dc *dc) |
657 | { | 811 | { |
658 | struct drm_device *drm = dc->base.dev; | 812 | struct drm_device *drm = dc->base.dev; |
@@ -729,8 +883,6 @@ static void tegra_dc_destroy(struct drm_crtc *crtc) | |||
729 | } | 883 | } |
730 | 884 | ||
731 | static const struct drm_crtc_funcs tegra_crtc_funcs = { | 885 | static const struct drm_crtc_funcs tegra_crtc_funcs = { |
732 | .cursor_set2 = tegra_dc_cursor_set2, | ||
733 | .cursor_move = tegra_dc_cursor_move, | ||
734 | .page_flip = tegra_dc_page_flip, | 886 | .page_flip = tegra_dc_page_flip, |
735 | .set_config = drm_crtc_helper_set_config, | 887 | .set_config = drm_crtc_helper_set_config, |
736 | .destroy = tegra_dc_destroy, | 888 | .destroy = tegra_dc_destroy, |
@@ -744,7 +896,7 @@ static void tegra_crtc_disable(struct drm_crtc *crtc) | |||
744 | 896 | ||
745 | drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) { | 897 | drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) { |
746 | if (plane->crtc == crtc) { | 898 | if (plane->crtc == crtc) { |
747 | tegra_plane_disable(plane); | 899 | tegra_window_plane_disable(plane); |
748 | plane->crtc = NULL; | 900 | plane->crtc = NULL; |
749 | 901 | ||
750 | if (plane->fb) { | 902 | if (plane->fb) { |
@@ -755,6 +907,7 @@ static void tegra_crtc_disable(struct drm_crtc *crtc) | |||
755 | } | 907 | } |
756 | 908 | ||
757 | drm_vblank_off(drm, dc->pipe); | 909 | drm_vblank_off(drm, dc->pipe); |
910 | tegra_dc_commit(dc); | ||
758 | } | 911 | } |
759 | 912 | ||
760 | static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, | 913 | static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, |
@@ -937,15 +1090,9 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc) | |||
937 | static void tegra_crtc_commit(struct drm_crtc *crtc) | 1090 | static void tegra_crtc_commit(struct drm_crtc *crtc) |
938 | { | 1091 | { |
939 | struct tegra_dc *dc = to_tegra_dc(crtc); | 1092 | struct tegra_dc *dc = to_tegra_dc(crtc); |
940 | unsigned long value; | ||
941 | |||
942 | value = GENERAL_UPDATE | WIN_A_UPDATE; | ||
943 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
944 | |||
945 | value = GENERAL_ACT_REQ | WIN_A_ACT_REQ; | ||
946 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
947 | 1093 | ||
948 | drm_vblank_post_modeset(crtc->dev, dc->pipe); | 1094 | drm_vblank_post_modeset(crtc->dev, dc->pipe); |
1095 | tegra_dc_commit(dc); | ||
949 | } | 1096 | } |
950 | 1097 | ||
951 | static void tegra_crtc_load_lut(struct drm_crtc *crtc) | 1098 | static void tegra_crtc_load_lut(struct drm_crtc *crtc) |
@@ -999,7 +1146,7 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data) | |||
999 | struct tegra_dc *dc = node->info_ent->data; | 1146 | struct tegra_dc *dc = node->info_ent->data; |
1000 | 1147 | ||
1001 | #define DUMP_REG(name) \ | 1148 | #define DUMP_REG(name) \ |
1002 | seq_printf(s, "%-40s %#05x %08lx\n", #name, name, \ | 1149 | seq_printf(s, "%-40s %#05x %08x\n", #name, name, \ |
1003 | tegra_dc_readl(dc, name)) | 1150 | tegra_dc_readl(dc, name)) |
1004 | 1151 | ||
1005 | DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT); | 1152 | DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT); |
@@ -1287,9 +1434,40 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1287 | struct drm_device *drm = dev_get_drvdata(client->parent); | 1434 | struct drm_device *drm = dev_get_drvdata(client->parent); |
1288 | struct tegra_dc *dc = host1x_client_to_dc(client); | 1435 | struct tegra_dc *dc = host1x_client_to_dc(client); |
1289 | struct tegra_drm *tegra = drm->dev_private; | 1436 | struct tegra_drm *tegra = drm->dev_private; |
1437 | struct drm_plane *primary = NULL; | ||
1438 | struct drm_plane *cursor = NULL; | ||
1290 | int err; | 1439 | int err; |
1291 | 1440 | ||
1292 | drm_crtc_init(drm, &dc->base, &tegra_crtc_funcs); | 1441 | if (tegra->domain) { |
1442 | err = iommu_attach_device(tegra->domain, dc->dev); | ||
1443 | if (err < 0) { | ||
1444 | dev_err(dc->dev, "failed to attach to domain: %d\n", | ||
1445 | err); | ||
1446 | return err; | ||
1447 | } | ||
1448 | |||
1449 | dc->domain = tegra->domain; | ||
1450 | } | ||
1451 | |||
1452 | primary = tegra_dc_primary_plane_create(drm, dc); | ||
1453 | if (IS_ERR(primary)) { | ||
1454 | err = PTR_ERR(primary); | ||
1455 | goto cleanup; | ||
1456 | } | ||
1457 | |||
1458 | if (dc->soc->supports_cursor) { | ||
1459 | cursor = tegra_dc_cursor_plane_create(drm, dc); | ||
1460 | if (IS_ERR(cursor)) { | ||
1461 | err = PTR_ERR(cursor); | ||
1462 | goto cleanup; | ||
1463 | } | ||
1464 | } | ||
1465 | |||
1466 | err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor, | ||
1467 | &tegra_crtc_funcs); | ||
1468 | if (err < 0) | ||
1469 | goto cleanup; | ||
1470 | |||
1293 | drm_mode_crtc_set_gamma_size(&dc->base, 256); | 1471 | drm_mode_crtc_set_gamma_size(&dc->base, 256); |
1294 | drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); | 1472 | drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); |
1295 | 1473 | ||
@@ -1303,12 +1481,12 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1303 | err = tegra_dc_rgb_init(drm, dc); | 1481 | err = tegra_dc_rgb_init(drm, dc); |
1304 | if (err < 0 && err != -ENODEV) { | 1482 | if (err < 0 && err != -ENODEV) { |
1305 | dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); | 1483 | dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); |
1306 | return err; | 1484 | goto cleanup; |
1307 | } | 1485 | } |
1308 | 1486 | ||
1309 | err = tegra_dc_add_planes(drm, dc); | 1487 | err = tegra_dc_add_planes(drm, dc); |
1310 | if (err < 0) | 1488 | if (err < 0) |
1311 | return err; | 1489 | goto cleanup; |
1312 | 1490 | ||
1313 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | 1491 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { |
1314 | err = tegra_dc_debugfs_init(dc, drm->primary); | 1492 | err = tegra_dc_debugfs_init(dc, drm->primary); |
@@ -1321,10 +1499,24 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1321 | if (err < 0) { | 1499 | if (err < 0) { |
1322 | dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, | 1500 | dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, |
1323 | err); | 1501 | err); |
1324 | return err; | 1502 | goto cleanup; |
1325 | } | 1503 | } |
1326 | 1504 | ||
1327 | return 0; | 1505 | return 0; |
1506 | |||
1507 | cleanup: | ||
1508 | if (cursor) | ||
1509 | drm_plane_cleanup(cursor); | ||
1510 | |||
1511 | if (primary) | ||
1512 | drm_plane_cleanup(primary); | ||
1513 | |||
1514 | if (tegra->domain) { | ||
1515 | iommu_detach_device(tegra->domain, dc->dev); | ||
1516 | dc->domain = NULL; | ||
1517 | } | ||
1518 | |||
1519 | return err; | ||
1328 | } | 1520 | } |
1329 | 1521 | ||
1330 | static int tegra_dc_exit(struct host1x_client *client) | 1522 | static int tegra_dc_exit(struct host1x_client *client) |
@@ -1346,6 +1538,11 @@ static int tegra_dc_exit(struct host1x_client *client) | |||
1346 | return err; | 1538 | return err; |
1347 | } | 1539 | } |
1348 | 1540 | ||
1541 | if (dc->domain) { | ||
1542 | iommu_detach_device(dc->domain, dc->dev); | ||
1543 | dc->domain = NULL; | ||
1544 | } | ||
1545 | |||
1349 | return 0; | 1546 | return 0; |
1350 | } | 1547 | } |
1351 | 1548 | ||
@@ -1359,6 +1556,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = { | |||
1359 | .supports_cursor = false, | 1556 | .supports_cursor = false, |
1360 | .supports_block_linear = false, | 1557 | .supports_block_linear = false, |
1361 | .pitch_align = 8, | 1558 | .pitch_align = 8, |
1559 | .has_powergate = false, | ||
1362 | }; | 1560 | }; |
1363 | 1561 | ||
1364 | static const struct tegra_dc_soc_info tegra30_dc_soc_info = { | 1562 | static const struct tegra_dc_soc_info tegra30_dc_soc_info = { |
@@ -1366,6 +1564,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = { | |||
1366 | .supports_cursor = false, | 1564 | .supports_cursor = false, |
1367 | .supports_block_linear = false, | 1565 | .supports_block_linear = false, |
1368 | .pitch_align = 8, | 1566 | .pitch_align = 8, |
1567 | .has_powergate = false, | ||
1369 | }; | 1568 | }; |
1370 | 1569 | ||
1371 | static const struct tegra_dc_soc_info tegra114_dc_soc_info = { | 1570 | static const struct tegra_dc_soc_info tegra114_dc_soc_info = { |
@@ -1373,6 +1572,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = { | |||
1373 | .supports_cursor = false, | 1572 | .supports_cursor = false, |
1374 | .supports_block_linear = false, | 1573 | .supports_block_linear = false, |
1375 | .pitch_align = 64, | 1574 | .pitch_align = 64, |
1575 | .has_powergate = true, | ||
1376 | }; | 1576 | }; |
1377 | 1577 | ||
1378 | static const struct tegra_dc_soc_info tegra124_dc_soc_info = { | 1578 | static const struct tegra_dc_soc_info tegra124_dc_soc_info = { |
@@ -1380,6 +1580,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = { | |||
1380 | .supports_cursor = true, | 1580 | .supports_cursor = true, |
1381 | .supports_block_linear = true, | 1581 | .supports_block_linear = true, |
1382 | .pitch_align = 64, | 1582 | .pitch_align = 64, |
1583 | .has_powergate = true, | ||
1383 | }; | 1584 | }; |
1384 | 1585 | ||
1385 | static const struct of_device_id tegra_dc_of_match[] = { | 1586 | static const struct of_device_id tegra_dc_of_match[] = { |
@@ -1387,6 +1588,9 @@ static const struct of_device_id tegra_dc_of_match[] = { | |||
1387 | .compatible = "nvidia,tegra124-dc", | 1588 | .compatible = "nvidia,tegra124-dc", |
1388 | .data = &tegra124_dc_soc_info, | 1589 | .data = &tegra124_dc_soc_info, |
1389 | }, { | 1590 | }, { |
1591 | .compatible = "nvidia,tegra114-dc", | ||
1592 | .data = &tegra114_dc_soc_info, | ||
1593 | }, { | ||
1390 | .compatible = "nvidia,tegra30-dc", | 1594 | .compatible = "nvidia,tegra30-dc", |
1391 | .data = &tegra30_dc_soc_info, | 1595 | .data = &tegra30_dc_soc_info, |
1392 | }, { | 1596 | }, { |
@@ -1469,9 +1673,34 @@ static int tegra_dc_probe(struct platform_device *pdev) | |||
1469 | return PTR_ERR(dc->rst); | 1673 | return PTR_ERR(dc->rst); |
1470 | } | 1674 | } |
1471 | 1675 | ||
1472 | err = clk_prepare_enable(dc->clk); | 1676 | if (dc->soc->has_powergate) { |
1473 | if (err < 0) | 1677 | if (dc->pipe == 0) |
1474 | return err; | 1678 | dc->powergate = TEGRA_POWERGATE_DIS; |
1679 | else | ||
1680 | dc->powergate = TEGRA_POWERGATE_DISB; | ||
1681 | |||
1682 | err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, | ||
1683 | dc->rst); | ||
1684 | if (err < 0) { | ||
1685 | dev_err(&pdev->dev, "failed to power partition: %d\n", | ||
1686 | err); | ||
1687 | return err; | ||
1688 | } | ||
1689 | } else { | ||
1690 | err = clk_prepare_enable(dc->clk); | ||
1691 | if (err < 0) { | ||
1692 | dev_err(&pdev->dev, "failed to enable clock: %d\n", | ||
1693 | err); | ||
1694 | return err; | ||
1695 | } | ||
1696 | |||
1697 | err = reset_control_deassert(dc->rst); | ||
1698 | if (err < 0) { | ||
1699 | dev_err(&pdev->dev, "failed to deassert reset: %d\n", | ||
1700 | err); | ||
1701 | return err; | ||
1702 | } | ||
1703 | } | ||
1475 | 1704 | ||
1476 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1705 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1477 | dc->regs = devm_ioremap_resource(&pdev->dev, regs); | 1706 | dc->regs = devm_ioremap_resource(&pdev->dev, regs); |
@@ -1525,6 +1754,10 @@ static int tegra_dc_remove(struct platform_device *pdev) | |||
1525 | } | 1754 | } |
1526 | 1755 | ||
1527 | reset_control_assert(dc->rst); | 1756 | reset_control_assert(dc->rst); |
1757 | |||
1758 | if (dc->soc->has_powergate) | ||
1759 | tegra_powergate_power_off(dc->powergate); | ||
1760 | |||
1528 | clk_disable_unprepare(dc->clk); | 1761 | clk_disable_unprepare(dc->clk); |
1529 | 1762 | ||
1530 | return 0; | 1763 | return 0; |
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 59736bb810cd..e549afeece1f 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
@@ -8,6 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/host1x.h> | 10 | #include <linux/host1x.h> |
11 | #include <linux/iommu.h> | ||
11 | 12 | ||
12 | #include "drm.h" | 13 | #include "drm.h" |
13 | #include "gem.h" | 14 | #include "gem.h" |
@@ -33,6 +34,17 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) | |||
33 | if (!tegra) | 34 | if (!tegra) |
34 | return -ENOMEM; | 35 | return -ENOMEM; |
35 | 36 | ||
37 | if (iommu_present(&platform_bus_type)) { | ||
38 | tegra->domain = iommu_domain_alloc(&platform_bus_type); | ||
39 | if (IS_ERR(tegra->domain)) { | ||
40 | err = PTR_ERR(tegra->domain); | ||
41 | goto free; | ||
42 | } | ||
43 | |||
44 | DRM_DEBUG("IOMMU context initialized\n"); | ||
45 | drm_mm_init(&tegra->mm, 0, SZ_2G); | ||
46 | } | ||
47 | |||
36 | mutex_init(&tegra->clients_lock); | 48 | mutex_init(&tegra->clients_lock); |
37 | INIT_LIST_HEAD(&tegra->clients); | 49 | INIT_LIST_HEAD(&tegra->clients); |
38 | drm->dev_private = tegra; | 50 | drm->dev_private = tegra; |
@@ -42,13 +54,13 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) | |||
42 | 54 | ||
43 | err = tegra_drm_fb_prepare(drm); | 55 | err = tegra_drm_fb_prepare(drm); |
44 | if (err < 0) | 56 | if (err < 0) |
45 | return err; | 57 | goto config; |
46 | 58 | ||
47 | drm_kms_helper_poll_init(drm); | 59 | drm_kms_helper_poll_init(drm); |
48 | 60 | ||
49 | err = host1x_device_init(device); | 61 | err = host1x_device_init(device); |
50 | if (err < 0) | 62 | if (err < 0) |
51 | return err; | 63 | goto fbdev; |
52 | 64 | ||
53 | /* | 65 | /* |
54 | * We don't use the drm_irq_install() helpers provided by the DRM | 66 | * We don't use the drm_irq_install() helpers provided by the DRM |
@@ -59,18 +71,37 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) | |||
59 | 71 | ||
60 | err = drm_vblank_init(drm, drm->mode_config.num_crtc); | 72 | err = drm_vblank_init(drm, drm->mode_config.num_crtc); |
61 | if (err < 0) | 73 | if (err < 0) |
62 | return err; | 74 | goto device; |
63 | 75 | ||
64 | err = tegra_drm_fb_init(drm); | 76 | err = tegra_drm_fb_init(drm); |
65 | if (err < 0) | 77 | if (err < 0) |
66 | return err; | 78 | goto vblank; |
67 | 79 | ||
68 | return 0; | 80 | return 0; |
81 | |||
82 | vblank: | ||
83 | drm_vblank_cleanup(drm); | ||
84 | device: | ||
85 | host1x_device_exit(device); | ||
86 | fbdev: | ||
87 | drm_kms_helper_poll_fini(drm); | ||
88 | tegra_drm_fb_free(drm); | ||
89 | config: | ||
90 | drm_mode_config_cleanup(drm); | ||
91 | |||
92 | if (tegra->domain) { | ||
93 | iommu_domain_free(tegra->domain); | ||
94 | drm_mm_takedown(&tegra->mm); | ||
95 | } | ||
96 | free: | ||
97 | kfree(tegra); | ||
98 | return err; | ||
69 | } | 99 | } |
70 | 100 | ||
71 | static int tegra_drm_unload(struct drm_device *drm) | 101 | static int tegra_drm_unload(struct drm_device *drm) |
72 | { | 102 | { |
73 | struct host1x_device *device = to_host1x_device(drm->dev); | 103 | struct host1x_device *device = to_host1x_device(drm->dev); |
104 | struct tegra_drm *tegra = drm->dev_private; | ||
74 | int err; | 105 | int err; |
75 | 106 | ||
76 | drm_kms_helper_poll_fini(drm); | 107 | drm_kms_helper_poll_fini(drm); |
@@ -82,6 +113,13 @@ static int tegra_drm_unload(struct drm_device *drm) | |||
82 | if (err < 0) | 113 | if (err < 0) |
83 | return err; | 114 | return err; |
84 | 115 | ||
116 | if (tegra->domain) { | ||
117 | iommu_domain_free(tegra->domain); | ||
118 | drm_mm_takedown(&tegra->mm); | ||
119 | } | ||
120 | |||
121 | kfree(tegra); | ||
122 | |||
85 | return 0; | 123 | return 0; |
86 | } | 124 | } |
87 | 125 | ||
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index e89c70fa82d5..3a3b2e7b5b3f 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h | |||
@@ -39,6 +39,9 @@ struct tegra_fbdev { | |||
39 | struct tegra_drm { | 39 | struct tegra_drm { |
40 | struct drm_device *drm; | 40 | struct drm_device *drm; |
41 | 41 | ||
42 | struct iommu_domain *domain; | ||
43 | struct drm_mm mm; | ||
44 | |||
42 | struct mutex clients_lock; | 45 | struct mutex clients_lock; |
43 | struct list_head clients; | 46 | struct list_head clients; |
44 | 47 | ||
@@ -101,6 +104,7 @@ struct tegra_dc { | |||
101 | spinlock_t lock; | 104 | spinlock_t lock; |
102 | 105 | ||
103 | struct drm_crtc base; | 106 | struct drm_crtc base; |
107 | int powergate; | ||
104 | int pipe; | 108 | int pipe; |
105 | 109 | ||
106 | struct clk *clk; | 110 | struct clk *clk; |
@@ -120,6 +124,8 @@ struct tegra_dc { | |||
120 | struct drm_pending_vblank_event *event; | 124 | struct drm_pending_vblank_event *event; |
121 | 125 | ||
122 | const struct tegra_dc_soc_info *soc; | 126 | const struct tegra_dc_soc_info *soc; |
127 | |||
128 | struct iommu_domain *domain; | ||
123 | }; | 129 | }; |
124 | 130 | ||
125 | static inline struct tegra_dc * | 131 | static inline struct tegra_dc * |
@@ -133,16 +139,15 @@ static inline struct tegra_dc *to_tegra_dc(struct drm_crtc *crtc) | |||
133 | return crtc ? container_of(crtc, struct tegra_dc, base) : NULL; | 139 | return crtc ? container_of(crtc, struct tegra_dc, base) : NULL; |
134 | } | 140 | } |
135 | 141 | ||
136 | static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long value, | 142 | static inline void tegra_dc_writel(struct tegra_dc *dc, u32 value, |
137 | unsigned long reg) | 143 | unsigned long offset) |
138 | { | 144 | { |
139 | writel(value, dc->regs + (reg << 2)); | 145 | writel(value, dc->regs + (offset << 2)); |
140 | } | 146 | } |
141 | 147 | ||
142 | static inline unsigned long tegra_dc_readl(struct tegra_dc *dc, | 148 | static inline u32 tegra_dc_readl(struct tegra_dc *dc, unsigned long offset) |
143 | unsigned long reg) | ||
144 | { | 149 | { |
145 | return readl(dc->regs + (reg << 2)); | 150 | return readl(dc->regs + (offset << 2)); |
146 | } | 151 | } |
147 | 152 | ||
148 | struct tegra_dc_window { | 153 | struct tegra_dc_window { |
@@ -287,6 +292,7 @@ bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer); | |||
287 | int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, | 292 | int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, |
288 | struct tegra_bo_tiling *tiling); | 293 | struct tegra_bo_tiling *tiling); |
289 | int tegra_drm_fb_prepare(struct drm_device *drm); | 294 | int tegra_drm_fb_prepare(struct drm_device *drm); |
295 | void tegra_drm_fb_free(struct drm_device *drm); | ||
290 | int tegra_drm_fb_init(struct drm_device *drm); | 296 | int tegra_drm_fb_init(struct drm_device *drm); |
291 | void tegra_drm_fb_exit(struct drm_device *drm); | 297 | void tegra_drm_fb_exit(struct drm_device *drm); |
292 | #ifdef CONFIG_DRM_TEGRA_FBDEV | 298 | #ifdef CONFIG_DRM_TEGRA_FBDEV |
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index f7874458926a..33f67fd601c6 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/host1x.h> | 11 | #include <linux/host1x.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/of.h> | 13 | #include <linux/of.h> |
14 | #include <linux/of_platform.h> | ||
14 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
15 | #include <linux/reset.h> | 16 | #include <linux/reset.h> |
16 | 17 | ||
@@ -26,9 +27,6 @@ | |||
26 | #include "dsi.h" | 27 | #include "dsi.h" |
27 | #include "mipi-phy.h" | 28 | #include "mipi-phy.h" |
28 | 29 | ||
29 | #define DSI_VIDEO_FIFO_DEPTH (1920 / 4) | ||
30 | #define DSI_HOST_FIFO_DEPTH 64 | ||
31 | |||
32 | struct tegra_dsi { | 30 | struct tegra_dsi { |
33 | struct host1x_client client; | 31 | struct host1x_client client; |
34 | struct tegra_output output; | 32 | struct tegra_output output; |
@@ -54,6 +52,13 @@ struct tegra_dsi { | |||
54 | 52 | ||
55 | struct regulator *vdd; | 53 | struct regulator *vdd; |
56 | bool enabled; | 54 | bool enabled; |
55 | |||
56 | unsigned int video_fifo_depth; | ||
57 | unsigned int host_fifo_depth; | ||
58 | |||
59 | /* for ganged-mode support */ | ||
60 | struct tegra_dsi *master; | ||
61 | struct tegra_dsi *slave; | ||
57 | }; | 62 | }; |
58 | 63 | ||
59 | static inline struct tegra_dsi * | 64 | static inline struct tegra_dsi * |
@@ -318,6 +323,21 @@ static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = { | |||
318 | [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4), | 323 | [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4), |
319 | }; | 324 | }; |
320 | 325 | ||
326 | static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = { | ||
327 | [ 0] = 0, | ||
328 | [ 1] = 0, | ||
329 | [ 2] = 0, | ||
330 | [ 3] = 0, | ||
331 | [ 4] = 0, | ||
332 | [ 5] = 0, | ||
333 | [ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP, | ||
334 | [ 7] = 0, | ||
335 | [ 8] = 0, | ||
336 | [ 9] = 0, | ||
337 | [10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP, | ||
338 | [11] = 0, | ||
339 | }; | ||
340 | |||
321 | static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi) | 341 | static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi) |
322 | { | 342 | { |
323 | struct mipi_dphy_timing timing; | 343 | struct mipi_dphy_timing timing; |
@@ -329,7 +349,7 @@ static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi) | |||
329 | if (rate < 0) | 349 | if (rate < 0) |
330 | return rate; | 350 | return rate; |
331 | 351 | ||
332 | period = DIV_ROUND_CLOSEST(1000000000UL, rate * 2); | 352 | period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate * 2); |
333 | 353 | ||
334 | err = mipi_dphy_timing_get_default(&timing, period); | 354 | err = mipi_dphy_timing_get_default(&timing, period); |
335 | if (err < 0) | 355 | if (err < 0) |
@@ -369,6 +389,9 @@ static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi) | |||
369 | DSI_TIMING_FIELD(timing.tago, period, 1); | 389 | DSI_TIMING_FIELD(timing.tago, period, 1); |
370 | tegra_dsi_writel(dsi, value, DSI_BTA_TIMING); | 390 | tegra_dsi_writel(dsi, value, DSI_BTA_TIMING); |
371 | 391 | ||
392 | if (dsi->slave) | ||
393 | return tegra_dsi_set_phy_timing(dsi->slave); | ||
394 | |||
372 | return 0; | 395 | return 0; |
373 | } | 396 | } |
374 | 397 | ||
@@ -426,26 +449,59 @@ static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format, | |||
426 | return 0; | 449 | return 0; |
427 | } | 450 | } |
428 | 451 | ||
429 | static int tegra_output_dsi_enable(struct tegra_output *output) | 452 | static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start, |
453 | unsigned int size) | ||
454 | { | ||
455 | u32 value; | ||
456 | |||
457 | tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START); | ||
458 | tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE); | ||
459 | |||
460 | value = DSI_GANGED_MODE_CONTROL_ENABLE; | ||
461 | tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL); | ||
462 | } | ||
463 | |||
464 | static void tegra_dsi_enable(struct tegra_dsi *dsi) | ||
465 | { | ||
466 | u32 value; | ||
467 | |||
468 | value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); | ||
469 | value |= DSI_POWER_CONTROL_ENABLE; | ||
470 | tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); | ||
471 | |||
472 | if (dsi->slave) | ||
473 | tegra_dsi_enable(dsi->slave); | ||
474 | } | ||
475 | |||
476 | static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi) | ||
477 | { | ||
478 | if (dsi->master) | ||
479 | return dsi->master->lanes + dsi->lanes; | ||
480 | |||
481 | if (dsi->slave) | ||
482 | return dsi->lanes + dsi->slave->lanes; | ||
483 | |||
484 | return dsi->lanes; | ||
485 | } | ||
486 | |||
487 | static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe, | ||
488 | const struct drm_display_mode *mode) | ||
430 | { | 489 | { |
431 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | ||
432 | struct drm_display_mode *mode = &dc->base.mode; | ||
433 | unsigned int hact, hsw, hbp, hfp, i, mul, div; | 490 | unsigned int hact, hsw, hbp, hfp, i, mul, div; |
434 | struct tegra_dsi *dsi = to_dsi(output); | ||
435 | enum tegra_dsi_format format; | 491 | enum tegra_dsi_format format; |
436 | unsigned long value; | ||
437 | const u32 *pkt_seq; | 492 | const u32 *pkt_seq; |
493 | u32 value; | ||
438 | int err; | 494 | int err; |
439 | 495 | ||
440 | if (dsi->enabled) | ||
441 | return 0; | ||
442 | |||
443 | if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { | 496 | if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { |
444 | DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n"); | 497 | DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n"); |
445 | pkt_seq = pkt_seq_video_non_burst_sync_pulses; | 498 | pkt_seq = pkt_seq_video_non_burst_sync_pulses; |
446 | } else { | 499 | } else if (dsi->flags & MIPI_DSI_MODE_VIDEO) { |
447 | DRM_DEBUG_KMS("Non-burst video mode with sync events\n"); | 500 | DRM_DEBUG_KMS("Non-burst video mode with sync events\n"); |
448 | pkt_seq = pkt_seq_video_non_burst_sync_events; | 501 | pkt_seq = pkt_seq_video_non_burst_sync_events; |
502 | } else { | ||
503 | DRM_DEBUG_KMS("Command mode\n"); | ||
504 | pkt_seq = pkt_seq_command_mode; | ||
449 | } | 505 | } |
450 | 506 | ||
451 | err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); | 507 | err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); |
@@ -456,61 +512,136 @@ static int tegra_output_dsi_enable(struct tegra_output *output) | |||
456 | if (err < 0) | 512 | if (err < 0) |
457 | return err; | 513 | return err; |
458 | 514 | ||
459 | err = clk_enable(dsi->clk); | ||
460 | if (err < 0) | ||
461 | return err; | ||
462 | |||
463 | reset_control_deassert(dsi->rst); | ||
464 | |||
465 | value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) | | 515 | value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) | |
466 | DSI_CONTROL_LANES(dsi->lanes - 1) | | 516 | DSI_CONTROL_LANES(dsi->lanes - 1) | |
467 | DSI_CONTROL_SOURCE(dc->pipe); | 517 | DSI_CONTROL_SOURCE(pipe); |
468 | tegra_dsi_writel(dsi, value, DSI_CONTROL); | 518 | tegra_dsi_writel(dsi, value, DSI_CONTROL); |
469 | 519 | ||
470 | tegra_dsi_writel(dsi, DSI_VIDEO_FIFO_DEPTH, DSI_MAX_THRESHOLD); | 520 | tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD); |
471 | 521 | ||
472 | value = DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | | 522 | value = DSI_HOST_CONTROL_HS; |
473 | DSI_HOST_CONTROL_ECC; | ||
474 | tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); | 523 | tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); |
475 | 524 | ||
476 | value = tegra_dsi_readl(dsi, DSI_CONTROL); | 525 | value = tegra_dsi_readl(dsi, DSI_CONTROL); |
526 | |||
477 | if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) | 527 | if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) |
478 | value |= DSI_CONTROL_HS_CLK_CTRL; | 528 | value |= DSI_CONTROL_HS_CLK_CTRL; |
529 | |||
479 | value &= ~DSI_CONTROL_TX_TRIG(3); | 530 | value &= ~DSI_CONTROL_TX_TRIG(3); |
480 | value &= ~DSI_CONTROL_DCS_ENABLE; | 531 | |
532 | /* enable DCS commands for command mode */ | ||
533 | if (dsi->flags & MIPI_DSI_MODE_VIDEO) | ||
534 | value &= ~DSI_CONTROL_DCS_ENABLE; | ||
535 | else | ||
536 | value |= DSI_CONTROL_DCS_ENABLE; | ||
537 | |||
481 | value |= DSI_CONTROL_VIDEO_ENABLE; | 538 | value |= DSI_CONTROL_VIDEO_ENABLE; |
482 | value &= ~DSI_CONTROL_HOST_ENABLE; | 539 | value &= ~DSI_CONTROL_HOST_ENABLE; |
483 | tegra_dsi_writel(dsi, value, DSI_CONTROL); | 540 | tegra_dsi_writel(dsi, value, DSI_CONTROL); |
484 | 541 | ||
485 | err = tegra_dsi_set_phy_timing(dsi); | ||
486 | if (err < 0) | ||
487 | return err; | ||
488 | |||
489 | for (i = 0; i < NUM_PKT_SEQ; i++) | 542 | for (i = 0; i < NUM_PKT_SEQ; i++) |
490 | tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i); | 543 | tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i); |
491 | 544 | ||
492 | /* horizontal active pixels */ | 545 | if (dsi->flags & MIPI_DSI_MODE_VIDEO) { |
493 | hact = mode->hdisplay * mul / div; | 546 | /* horizontal active pixels */ |
547 | hact = mode->hdisplay * mul / div; | ||
494 | 548 | ||
495 | /* horizontal sync width */ | 549 | /* horizontal sync width */ |
496 | hsw = (mode->hsync_end - mode->hsync_start) * mul / div; | 550 | hsw = (mode->hsync_end - mode->hsync_start) * mul / div; |
497 | hsw -= 10; | 551 | hsw -= 10; |
498 | 552 | ||
499 | /* horizontal back porch */ | 553 | /* horizontal back porch */ |
500 | hbp = (mode->htotal - mode->hsync_end) * mul / div; | 554 | hbp = (mode->htotal - mode->hsync_end) * mul / div; |
501 | hbp -= 14; | 555 | hbp -= 14; |
502 | 556 | ||
503 | /* horizontal front porch */ | 557 | /* horizontal front porch */ |
504 | hfp = (mode->hsync_start - mode->hdisplay) * mul / div; | 558 | hfp = (mode->hsync_start - mode->hdisplay) * mul / div; |
505 | hfp -= 8; | 559 | hfp -= 8; |
506 | 560 | ||
507 | tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1); | 561 | tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1); |
508 | tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3); | 562 | tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3); |
509 | tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5); | 563 | tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5); |
510 | tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7); | 564 | tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7); |
511 | 565 | ||
512 | /* set SOL delay */ | 566 | /* set SOL delay (for non-burst mode only) */ |
513 | tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY); | 567 | tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY); |
568 | |||
569 | /* TODO: implement ganged mode */ | ||
570 | } else { | ||
571 | u16 bytes; | ||
572 | |||
573 | if (dsi->master || dsi->slave) { | ||
574 | /* | ||
575 | * For ganged mode, assume symmetric left-right mode. | ||
576 | */ | ||
577 | bytes = 1 + (mode->hdisplay / 2) * mul / div; | ||
578 | } else { | ||
579 | /* 1 byte (DCS command) + pixel data */ | ||
580 | bytes = 1 + mode->hdisplay * mul / div; | ||
581 | } | ||
582 | |||
583 | tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1); | ||
584 | tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3); | ||
585 | tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5); | ||
586 | tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7); | ||
587 | |||
588 | value = MIPI_DCS_WRITE_MEMORY_START << 8 | | ||
589 | MIPI_DCS_WRITE_MEMORY_CONTINUE; | ||
590 | tegra_dsi_writel(dsi, value, DSI_DCS_CMDS); | ||
591 | |||
592 | /* set SOL delay */ | ||
593 | if (dsi->master || dsi->slave) { | ||
594 | unsigned int lanes = tegra_dsi_get_lanes(dsi); | ||
595 | unsigned long delay, bclk, bclk_ganged; | ||
596 | |||
597 | /* SOL to valid, valid to FIFO and FIFO write delay */ | ||
598 | delay = 4 + 4 + 2; | ||
599 | delay = DIV_ROUND_UP(delay * mul, div * lanes); | ||
600 | /* FIFO read delay */ | ||
601 | delay = delay + 6; | ||
602 | |||
603 | bclk = DIV_ROUND_UP(mode->htotal * mul, div * lanes); | ||
604 | bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes); | ||
605 | value = bclk - bclk_ganged + delay + 20; | ||
606 | } else { | ||
607 | /* TODO: revisit for non-ganged mode */ | ||
608 | value = 8 * mul / div; | ||
609 | } | ||
610 | |||
611 | tegra_dsi_writel(dsi, value, DSI_SOL_DELAY); | ||
612 | } | ||
613 | |||
614 | if (dsi->slave) { | ||
615 | err = tegra_dsi_configure(dsi->slave, pipe, mode); | ||
616 | if (err < 0) | ||
617 | return err; | ||
618 | |||
619 | /* | ||
620 | * TODO: Support modes other than symmetrical left-right | ||
621 | * split. | ||
622 | */ | ||
623 | tegra_dsi_ganged_enable(dsi, 0, mode->hdisplay / 2); | ||
624 | tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2, | ||
625 | mode->hdisplay / 2); | ||
626 | } | ||
627 | |||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static int tegra_output_dsi_enable(struct tegra_output *output) | ||
632 | { | ||
633 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | ||
634 | const struct drm_display_mode *mode = &dc->base.mode; | ||
635 | struct tegra_dsi *dsi = to_dsi(output); | ||
636 | u32 value; | ||
637 | int err; | ||
638 | |||
639 | if (dsi->enabled) | ||
640 | return 0; | ||
641 | |||
642 | err = tegra_dsi_configure(dsi, dc->pipe, mode); | ||
643 | if (err < 0) | ||
644 | return err; | ||
514 | 645 | ||
515 | /* enable display controller */ | 646 | /* enable display controller */ |
516 | value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); | 647 | value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); |
@@ -531,28 +662,79 @@ static int tegra_output_dsi_enable(struct tegra_output *output) | |||
531 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | 662 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); |
532 | 663 | ||
533 | /* enable DSI controller */ | 664 | /* enable DSI controller */ |
534 | value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); | 665 | tegra_dsi_enable(dsi); |
535 | value |= DSI_POWER_CONTROL_ENABLE; | ||
536 | tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); | ||
537 | 666 | ||
538 | dsi->enabled = true; | 667 | dsi->enabled = true; |
539 | 668 | ||
540 | return 0; | 669 | return 0; |
541 | } | 670 | } |
542 | 671 | ||
672 | static int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout) | ||
673 | { | ||
674 | u32 value; | ||
675 | |||
676 | timeout = jiffies + msecs_to_jiffies(timeout); | ||
677 | |||
678 | while (time_before(jiffies, timeout)) { | ||
679 | value = tegra_dsi_readl(dsi, DSI_STATUS); | ||
680 | if (value & DSI_STATUS_IDLE) | ||
681 | return 0; | ||
682 | |||
683 | usleep_range(1000, 2000); | ||
684 | } | ||
685 | |||
686 | return -ETIMEDOUT; | ||
687 | } | ||
688 | |||
689 | static void tegra_dsi_video_disable(struct tegra_dsi *dsi) | ||
690 | { | ||
691 | u32 value; | ||
692 | |||
693 | value = tegra_dsi_readl(dsi, DSI_CONTROL); | ||
694 | value &= ~DSI_CONTROL_VIDEO_ENABLE; | ||
695 | tegra_dsi_writel(dsi, value, DSI_CONTROL); | ||
696 | |||
697 | if (dsi->slave) | ||
698 | tegra_dsi_video_disable(dsi->slave); | ||
699 | } | ||
700 | |||
701 | static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi) | ||
702 | { | ||
703 | tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START); | ||
704 | tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE); | ||
705 | tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL); | ||
706 | } | ||
707 | |||
708 | static void tegra_dsi_disable(struct tegra_dsi *dsi) | ||
709 | { | ||
710 | u32 value; | ||
711 | |||
712 | if (dsi->slave) { | ||
713 | tegra_dsi_ganged_disable(dsi->slave); | ||
714 | tegra_dsi_ganged_disable(dsi); | ||
715 | } | ||
716 | |||
717 | value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); | ||
718 | value &= ~DSI_POWER_CONTROL_ENABLE; | ||
719 | tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); | ||
720 | |||
721 | if (dsi->slave) | ||
722 | tegra_dsi_disable(dsi->slave); | ||
723 | |||
724 | usleep_range(5000, 10000); | ||
725 | } | ||
726 | |||
543 | static int tegra_output_dsi_disable(struct tegra_output *output) | 727 | static int tegra_output_dsi_disable(struct tegra_output *output) |
544 | { | 728 | { |
545 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | 729 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); |
546 | struct tegra_dsi *dsi = to_dsi(output); | 730 | struct tegra_dsi *dsi = to_dsi(output); |
547 | unsigned long value; | 731 | unsigned long value; |
732 | int err; | ||
548 | 733 | ||
549 | if (!dsi->enabled) | 734 | if (!dsi->enabled) |
550 | return 0; | 735 | return 0; |
551 | 736 | ||
552 | /* disable DSI controller */ | 737 | tegra_dsi_video_disable(dsi); |
553 | value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); | ||
554 | value &= ~DSI_POWER_CONTROL_ENABLE; | ||
555 | tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); | ||
556 | 738 | ||
557 | /* | 739 | /* |
558 | * The following accesses registers of the display controller, so make | 740 | * The following accesses registers of the display controller, so make |
@@ -576,39 +758,68 @@ static int tegra_output_dsi_disable(struct tegra_output *output) | |||
576 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | 758 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); |
577 | } | 759 | } |
578 | 760 | ||
579 | clk_disable(dsi->clk); | 761 | err = tegra_dsi_wait_idle(dsi, 100); |
762 | if (err < 0) | ||
763 | dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err); | ||
764 | |||
765 | tegra_dsi_disable(dsi); | ||
580 | 766 | ||
581 | dsi->enabled = false; | 767 | dsi->enabled = false; |
582 | 768 | ||
583 | return 0; | 769 | return 0; |
584 | } | 770 | } |
585 | 771 | ||
772 | static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk, | ||
773 | unsigned int vrefresh) | ||
774 | { | ||
775 | unsigned int timeout; | ||
776 | u32 value; | ||
777 | |||
778 | /* one frame high-speed transmission timeout */ | ||
779 | timeout = (bclk / vrefresh) / 512; | ||
780 | value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout); | ||
781 | tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0); | ||
782 | |||
783 | /* 2 ms peripheral timeout for panel */ | ||
784 | timeout = 2 * bclk / 512 * 1000; | ||
785 | value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000); | ||
786 | tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1); | ||
787 | |||
788 | value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0); | ||
789 | tegra_dsi_writel(dsi, value, DSI_TO_TALLY); | ||
790 | |||
791 | if (dsi->slave) | ||
792 | tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh); | ||
793 | } | ||
794 | |||
586 | static int tegra_output_dsi_setup_clock(struct tegra_output *output, | 795 | static int tegra_output_dsi_setup_clock(struct tegra_output *output, |
587 | struct clk *clk, unsigned long pclk, | 796 | struct clk *clk, unsigned long pclk, |
588 | unsigned int *divp) | 797 | unsigned int *divp) |
589 | { | 798 | { |
590 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | 799 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); |
591 | struct drm_display_mode *mode = &dc->base.mode; | 800 | struct drm_display_mode *mode = &dc->base.mode; |
592 | unsigned int timeout, mul, div, vrefresh; | ||
593 | struct tegra_dsi *dsi = to_dsi(output); | 801 | struct tegra_dsi *dsi = to_dsi(output); |
594 | unsigned long bclk, plld, value; | 802 | unsigned int mul, div, vrefresh, lanes; |
803 | unsigned long bclk, plld; | ||
595 | int err; | 804 | int err; |
596 | 805 | ||
806 | lanes = tegra_dsi_get_lanes(dsi); | ||
807 | |||
597 | err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); | 808 | err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); |
598 | if (err < 0) | 809 | if (err < 0) |
599 | return err; | 810 | return err; |
600 | 811 | ||
601 | DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, dsi->lanes); | 812 | DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, lanes); |
602 | vrefresh = drm_mode_vrefresh(mode); | 813 | vrefresh = drm_mode_vrefresh(mode); |
603 | DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh); | 814 | DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh); |
604 | 815 | ||
605 | /* compute byte clock */ | 816 | /* compute byte clock */ |
606 | bclk = (pclk * mul) / (div * dsi->lanes); | 817 | bclk = (pclk * mul) / (div * lanes); |
607 | 818 | ||
608 | /* | 819 | /* |
609 | * Compute bit clock and round up to the next MHz. | 820 | * Compute bit clock and round up to the next MHz. |
610 | */ | 821 | */ |
611 | plld = DIV_ROUND_UP(bclk * 8, 1000000) * 1000000; | 822 | plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC) * USEC_PER_SEC; |
612 | 823 | ||
613 | /* | 824 | /* |
614 | * We divide the frequency by two here, but we make up for that by | 825 | * We divide the frequency by two here, but we make up for that by |
@@ -640,25 +851,17 @@ static int tegra_output_dsi_setup_clock(struct tegra_output *output, | |||
640 | * not working properly otherwise. Perhaps the PLLs cannot generate | 851 | * not working properly otherwise. Perhaps the PLLs cannot generate |
641 | * frequencies sufficiently high. | 852 | * frequencies sufficiently high. |
642 | */ | 853 | */ |
643 | *divp = ((8 * mul) / (div * dsi->lanes)) - 2; | 854 | *divp = ((8 * mul) / (div * lanes)) - 2; |
644 | 855 | ||
645 | /* | 856 | /* |
646 | * XXX: Move the below somewhere else so that we don't need to have | 857 | * XXX: Move the below somewhere else so that we don't need to have |
647 | * access to the vrefresh in this function? | 858 | * access to the vrefresh in this function? |
648 | */ | 859 | */ |
860 | tegra_dsi_set_timeout(dsi, bclk, vrefresh); | ||
649 | 861 | ||
650 | /* one frame high-speed transmission timeout */ | 862 | err = tegra_dsi_set_phy_timing(dsi); |
651 | timeout = (bclk / vrefresh) / 512; | 863 | if (err < 0) |
652 | value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout); | 864 | return err; |
653 | tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0); | ||
654 | |||
655 | /* 2 ms peripheral timeout for panel */ | ||
656 | timeout = 2 * bclk / 512 * 1000; | ||
657 | value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000); | ||
658 | tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1); | ||
659 | |||
660 | value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0); | ||
661 | tegra_dsi_writel(dsi, value, DSI_TO_TALLY); | ||
662 | 865 | ||
663 | return 0; | 866 | return 0; |
664 | } | 867 | } |
@@ -695,7 +898,7 @@ static int tegra_dsi_pad_enable(struct tegra_dsi *dsi) | |||
695 | 898 | ||
696 | static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi) | 899 | static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi) |
697 | { | 900 | { |
698 | unsigned long value; | 901 | u32 value; |
699 | 902 | ||
700 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0); | 903 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0); |
701 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1); | 904 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1); |
@@ -720,14 +923,17 @@ static int tegra_dsi_init(struct host1x_client *client) | |||
720 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); | 923 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); |
721 | int err; | 924 | int err; |
722 | 925 | ||
723 | dsi->output.type = TEGRA_OUTPUT_DSI; | 926 | /* Gangsters must not register their own outputs. */ |
724 | dsi->output.dev = client->dev; | 927 | if (!dsi->master) { |
725 | dsi->output.ops = &dsi_ops; | 928 | dsi->output.type = TEGRA_OUTPUT_DSI; |
726 | 929 | dsi->output.dev = client->dev; | |
727 | err = tegra_output_init(drm, &dsi->output); | 930 | dsi->output.ops = &dsi_ops; |
728 | if (err < 0) { | 931 | |
729 | dev_err(client->dev, "output setup failed: %d\n", err); | 932 | err = tegra_output_init(drm, &dsi->output); |
730 | return err; | 933 | if (err < 0) { |
934 | dev_err(client->dev, "output setup failed: %d\n", err); | ||
935 | return err; | ||
936 | } | ||
731 | } | 937 | } |
732 | 938 | ||
733 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | 939 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { |
@@ -736,12 +942,6 @@ static int tegra_dsi_init(struct host1x_client *client) | |||
736 | dev_err(dsi->dev, "debugfs setup failed: %d\n", err); | 942 | dev_err(dsi->dev, "debugfs setup failed: %d\n", err); |
737 | } | 943 | } |
738 | 944 | ||
739 | err = tegra_dsi_pad_calibrate(dsi); | ||
740 | if (err < 0) { | ||
741 | dev_err(dsi->dev, "MIPI calibration failed: %d\n", err); | ||
742 | return err; | ||
743 | } | ||
744 | |||
745 | return 0; | 945 | return 0; |
746 | } | 946 | } |
747 | 947 | ||
@@ -756,16 +956,20 @@ static int tegra_dsi_exit(struct host1x_client *client) | |||
756 | dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err); | 956 | dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err); |
757 | } | 957 | } |
758 | 958 | ||
759 | err = tegra_output_disable(&dsi->output); | 959 | if (!dsi->master) { |
760 | if (err < 0) { | 960 | err = tegra_output_disable(&dsi->output); |
761 | dev_err(client->dev, "output failed to disable: %d\n", err); | 961 | if (err < 0) { |
762 | return err; | 962 | dev_err(client->dev, "output failed to disable: %d\n", |
763 | } | 963 | err); |
764 | 964 | return err; | |
765 | err = tegra_output_exit(&dsi->output); | 965 | } |
766 | if (err < 0) { | 966 | |
767 | dev_err(client->dev, "output cleanup failed: %d\n", err); | 967 | err = tegra_output_exit(&dsi->output); |
768 | return err; | 968 | if (err < 0) { |
969 | dev_err(client->dev, "output cleanup failed: %d\n", | ||
970 | err); | ||
971 | return err; | ||
972 | } | ||
769 | } | 973 | } |
770 | 974 | ||
771 | return 0; | 975 | return 0; |
@@ -792,20 +996,324 @@ static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi) | |||
792 | return 0; | 996 | return 0; |
793 | } | 997 | } |
794 | 998 | ||
999 | static const char * const error_report[16] = { | ||
1000 | "SoT Error", | ||
1001 | "SoT Sync Error", | ||
1002 | "EoT Sync Error", | ||
1003 | "Escape Mode Entry Command Error", | ||
1004 | "Low-Power Transmit Sync Error", | ||
1005 | "Peripheral Timeout Error", | ||
1006 | "False Control Error", | ||
1007 | "Contention Detected", | ||
1008 | "ECC Error, single-bit", | ||
1009 | "ECC Error, multi-bit", | ||
1010 | "Checksum Error", | ||
1011 | "DSI Data Type Not Recognized", | ||
1012 | "DSI VC ID Invalid", | ||
1013 | "Invalid Transmission Length", | ||
1014 | "Reserved", | ||
1015 | "DSI Protocol Violation", | ||
1016 | }; | ||
1017 | |||
1018 | static ssize_t tegra_dsi_read_response(struct tegra_dsi *dsi, | ||
1019 | const struct mipi_dsi_msg *msg, | ||
1020 | size_t count) | ||
1021 | { | ||
1022 | u8 *rx = msg->rx_buf; | ||
1023 | unsigned int i, j, k; | ||
1024 | size_t size = 0; | ||
1025 | u16 errors; | ||
1026 | u32 value; | ||
1027 | |||
1028 | /* read and parse packet header */ | ||
1029 | value = tegra_dsi_readl(dsi, DSI_RD_DATA); | ||
1030 | |||
1031 | switch (value & 0x3f) { | ||
1032 | case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: | ||
1033 | errors = (value >> 8) & 0xffff; | ||
1034 | dev_dbg(dsi->dev, "Acknowledge and error report: %04x\n", | ||
1035 | errors); | ||
1036 | for (i = 0; i < ARRAY_SIZE(error_report); i++) | ||
1037 | if (errors & BIT(i)) | ||
1038 | dev_dbg(dsi->dev, " %2u: %s\n", i, | ||
1039 | error_report[i]); | ||
1040 | break; | ||
1041 | |||
1042 | case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: | ||
1043 | rx[0] = (value >> 8) & 0xff; | ||
1044 | size = 1; | ||
1045 | break; | ||
1046 | |||
1047 | case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: | ||
1048 | rx[0] = (value >> 8) & 0xff; | ||
1049 | rx[1] = (value >> 16) & 0xff; | ||
1050 | size = 2; | ||
1051 | break; | ||
1052 | |||
1053 | case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE: | ||
1054 | size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff); | ||
1055 | break; | ||
1056 | |||
1057 | case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE: | ||
1058 | size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff); | ||
1059 | break; | ||
1060 | |||
1061 | default: | ||
1062 | dev_err(dsi->dev, "unhandled response type: %02x\n", | ||
1063 | value & 0x3f); | ||
1064 | return -EPROTO; | ||
1065 | } | ||
1066 | |||
1067 | size = min(size, msg->rx_len); | ||
1068 | |||
1069 | if (msg->rx_buf && size > 0) { | ||
1070 | for (i = 0, j = 0; i < count - 1; i++, j += 4) { | ||
1071 | u8 *rx = msg->rx_buf + j; | ||
1072 | |||
1073 | value = tegra_dsi_readl(dsi, DSI_RD_DATA); | ||
1074 | |||
1075 | for (k = 0; k < 4 && (j + k) < msg->rx_len; k++) | ||
1076 | rx[j + k] = (value >> (k << 3)) & 0xff; | ||
1077 | } | ||
1078 | } | ||
1079 | |||
1080 | return size; | ||
1081 | } | ||
1082 | |||
1083 | static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout) | ||
1084 | { | ||
1085 | tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER); | ||
1086 | |||
1087 | timeout = jiffies + msecs_to_jiffies(timeout); | ||
1088 | |||
1089 | while (time_before(jiffies, timeout)) { | ||
1090 | u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER); | ||
1091 | if ((value & DSI_TRIGGER_HOST) == 0) | ||
1092 | return 0; | ||
1093 | |||
1094 | usleep_range(1000, 2000); | ||
1095 | } | ||
1096 | |||
1097 | DRM_DEBUG_KMS("timeout waiting for transmission to complete\n"); | ||
1098 | return -ETIMEDOUT; | ||
1099 | } | ||
1100 | |||
1101 | static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi, | ||
1102 | unsigned long timeout) | ||
1103 | { | ||
1104 | timeout = jiffies + msecs_to_jiffies(250); | ||
1105 | |||
1106 | while (time_before(jiffies, timeout)) { | ||
1107 | u32 value = tegra_dsi_readl(dsi, DSI_STATUS); | ||
1108 | u8 count = value & 0x1f; | ||
1109 | |||
1110 | if (count > 0) | ||
1111 | return count; | ||
1112 | |||
1113 | usleep_range(1000, 2000); | ||
1114 | } | ||
1115 | |||
1116 | DRM_DEBUG_KMS("peripheral returned no data\n"); | ||
1117 | return -ETIMEDOUT; | ||
1118 | } | ||
1119 | |||
1120 | static void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset, | ||
1121 | const void *buffer, size_t size) | ||
1122 | { | ||
1123 | const u8 *buf = buffer; | ||
1124 | size_t i, j; | ||
1125 | u32 value; | ||
1126 | |||
1127 | for (j = 0; j < size; j += 4) { | ||
1128 | value = 0; | ||
1129 | |||
1130 | for (i = 0; i < 4 && j + i < size; i++) | ||
1131 | value |= buf[j + i] << (i << 3); | ||
1132 | |||
1133 | tegra_dsi_writel(dsi, value, DSI_WR_DATA); | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host, | ||
1138 | const struct mipi_dsi_msg *msg) | ||
1139 | { | ||
1140 | struct tegra_dsi *dsi = host_to_tegra(host); | ||
1141 | struct mipi_dsi_packet packet; | ||
1142 | const u8 *header; | ||
1143 | size_t count; | ||
1144 | ssize_t err; | ||
1145 | u32 value; | ||
1146 | |||
1147 | err = mipi_dsi_create_packet(&packet, msg); | ||
1148 | if (err < 0) | ||
1149 | return err; | ||
1150 | |||
1151 | header = packet.header; | ||
1152 | |||
1153 | /* maximum FIFO depth is 1920 words */ | ||
1154 | if (packet.size > dsi->video_fifo_depth * 4) | ||
1155 | return -ENOSPC; | ||
1156 | |||
1157 | /* reset underflow/overflow flags */ | ||
1158 | value = tegra_dsi_readl(dsi, DSI_STATUS); | ||
1159 | if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) { | ||
1160 | value = DSI_HOST_CONTROL_FIFO_RESET; | ||
1161 | tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); | ||
1162 | usleep_range(10, 20); | ||
1163 | } | ||
1164 | |||
1165 | value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); | ||
1166 | value |= DSI_POWER_CONTROL_ENABLE; | ||
1167 | tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); | ||
1168 | |||
1169 | usleep_range(5000, 10000); | ||
1170 | |||
1171 | value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | | ||
1172 | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC; | ||
1173 | |||
1174 | if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0) | ||
1175 | value |= DSI_HOST_CONTROL_HS; | ||
1176 | |||
1177 | /* | ||
1178 | * The host FIFO has a maximum of 64 words, so larger transmissions | ||
1179 | * need to use the video FIFO. | ||
1180 | */ | ||
1181 | if (packet.size > dsi->host_fifo_depth * 4) | ||
1182 | value |= DSI_HOST_CONTROL_FIFO_SEL; | ||
1183 | |||
1184 | tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); | ||
1185 | |||
1186 | /* | ||
1187 | * For reads and messages with explicitly requested ACK, generate a | ||
1188 | * BTA sequence after the transmission of the packet. | ||
1189 | */ | ||
1190 | if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) || | ||
1191 | (msg->rx_buf && msg->rx_len > 0)) { | ||
1192 | value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL); | ||
1193 | value |= DSI_HOST_CONTROL_PKT_BTA; | ||
1194 | tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); | ||
1195 | } | ||
1196 | |||
1197 | value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE; | ||
1198 | tegra_dsi_writel(dsi, value, DSI_CONTROL); | ||
1199 | |||
1200 | /* write packet header, ECC is generated by hardware */ | ||
1201 | value = header[2] << 16 | header[1] << 8 | header[0]; | ||
1202 | tegra_dsi_writel(dsi, value, DSI_WR_DATA); | ||
1203 | |||
1204 | /* write payload (if any) */ | ||
1205 | if (packet.payload_length > 0) | ||
1206 | tegra_dsi_writesl(dsi, DSI_WR_DATA, packet.payload, | ||
1207 | packet.payload_length); | ||
1208 | |||
1209 | err = tegra_dsi_transmit(dsi, 250); | ||
1210 | if (err < 0) | ||
1211 | return err; | ||
1212 | |||
1213 | if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) || | ||
1214 | (msg->rx_buf && msg->rx_len > 0)) { | ||
1215 | err = tegra_dsi_wait_for_response(dsi, 250); | ||
1216 | if (err < 0) | ||
1217 | return err; | ||
1218 | |||
1219 | count = err; | ||
1220 | |||
1221 | value = tegra_dsi_readl(dsi, DSI_RD_DATA); | ||
1222 | switch (value) { | ||
1223 | case 0x84: | ||
1224 | /* | ||
1225 | dev_dbg(dsi->dev, "ACK\n"); | ||
1226 | */ | ||
1227 | break; | ||
1228 | |||
1229 | case 0x87: | ||
1230 | /* | ||
1231 | dev_dbg(dsi->dev, "ESCAPE\n"); | ||
1232 | */ | ||
1233 | break; | ||
1234 | |||
1235 | default: | ||
1236 | dev_err(dsi->dev, "unknown status: %08x\n", value); | ||
1237 | break; | ||
1238 | } | ||
1239 | |||
1240 | if (count > 1) { | ||
1241 | err = tegra_dsi_read_response(dsi, msg, count); | ||
1242 | if (err < 0) | ||
1243 | dev_err(dsi->dev, | ||
1244 | "failed to parse response: %zd\n", | ||
1245 | err); | ||
1246 | else { | ||
1247 | /* | ||
1248 | * For read commands, return the number of | ||
1249 | * bytes returned by the peripheral. | ||
1250 | */ | ||
1251 | count = err; | ||
1252 | } | ||
1253 | } | ||
1254 | } else { | ||
1255 | /* | ||
1256 | * For write commands, we have transmitted the 4-byte header | ||
1257 | * plus the variable-length payload. | ||
1258 | */ | ||
1259 | count = 4 + packet.payload_length; | ||
1260 | } | ||
1261 | |||
1262 | return count; | ||
1263 | } | ||
1264 | |||
1265 | static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi) | ||
1266 | { | ||
1267 | struct clk *parent; | ||
1268 | int err; | ||
1269 | |||
1270 | /* make sure both DSI controllers share the same PLL */ | ||
1271 | parent = clk_get_parent(dsi->slave->clk); | ||
1272 | if (!parent) | ||
1273 | return -EINVAL; | ||
1274 | |||
1275 | err = clk_set_parent(parent, dsi->clk_parent); | ||
1276 | if (err < 0) | ||
1277 | return err; | ||
1278 | |||
1279 | return 0; | ||
1280 | } | ||
1281 | |||
795 | static int tegra_dsi_host_attach(struct mipi_dsi_host *host, | 1282 | static int tegra_dsi_host_attach(struct mipi_dsi_host *host, |
796 | struct mipi_dsi_device *device) | 1283 | struct mipi_dsi_device *device) |
797 | { | 1284 | { |
798 | struct tegra_dsi *dsi = host_to_tegra(host); | 1285 | struct tegra_dsi *dsi = host_to_tegra(host); |
799 | struct tegra_output *output = &dsi->output; | ||
800 | 1286 | ||
801 | dsi->flags = device->mode_flags; | 1287 | dsi->flags = device->mode_flags; |
802 | dsi->format = device->format; | 1288 | dsi->format = device->format; |
803 | dsi->lanes = device->lanes; | 1289 | dsi->lanes = device->lanes; |
804 | 1290 | ||
805 | output->panel = of_drm_find_panel(device->dev.of_node); | 1291 | if (dsi->slave) { |
806 | if (output->panel) { | 1292 | int err; |
807 | if (output->connector.dev) | 1293 | |
1294 | dev_dbg(dsi->dev, "attaching dual-channel device %s\n", | ||
1295 | dev_name(&device->dev)); | ||
1296 | |||
1297 | err = tegra_dsi_ganged_setup(dsi); | ||
1298 | if (err < 0) { | ||
1299 | dev_err(dsi->dev, "failed to set up ganged mode: %d\n", | ||
1300 | err); | ||
1301 | return err; | ||
1302 | } | ||
1303 | } | ||
1304 | |||
1305 | /* | ||
1306 | * Slaves don't have a panel associated with them, so they provide | ||
1307 | * merely the second channel. | ||
1308 | */ | ||
1309 | if (!dsi->master) { | ||
1310 | struct tegra_output *output = &dsi->output; | ||
1311 | |||
1312 | output->panel = of_drm_find_panel(device->dev.of_node); | ||
1313 | if (output->panel && output->connector.dev) { | ||
1314 | drm_panel_attach(output->panel, &output->connector); | ||
808 | drm_helper_hpd_irq_event(output->connector.dev); | 1315 | drm_helper_hpd_irq_event(output->connector.dev); |
1316 | } | ||
809 | } | 1317 | } |
810 | 1318 | ||
811 | return 0; | 1319 | return 0; |
@@ -818,10 +1326,10 @@ static int tegra_dsi_host_detach(struct mipi_dsi_host *host, | |||
818 | struct tegra_output *output = &dsi->output; | 1326 | struct tegra_output *output = &dsi->output; |
819 | 1327 | ||
820 | if (output->panel && &device->dev == output->panel->dev) { | 1328 | if (output->panel && &device->dev == output->panel->dev) { |
1329 | output->panel = NULL; | ||
1330 | |||
821 | if (output->connector.dev) | 1331 | if (output->connector.dev) |
822 | drm_helper_hpd_irq_event(output->connector.dev); | 1332 | drm_helper_hpd_irq_event(output->connector.dev); |
823 | |||
824 | output->panel = NULL; | ||
825 | } | 1333 | } |
826 | 1334 | ||
827 | return 0; | 1335 | return 0; |
@@ -830,8 +1338,29 @@ static int tegra_dsi_host_detach(struct mipi_dsi_host *host, | |||
830 | static const struct mipi_dsi_host_ops tegra_dsi_host_ops = { | 1338 | static const struct mipi_dsi_host_ops tegra_dsi_host_ops = { |
831 | .attach = tegra_dsi_host_attach, | 1339 | .attach = tegra_dsi_host_attach, |
832 | .detach = tegra_dsi_host_detach, | 1340 | .detach = tegra_dsi_host_detach, |
1341 | .transfer = tegra_dsi_host_transfer, | ||
833 | }; | 1342 | }; |
834 | 1343 | ||
1344 | static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) | ||
1345 | { | ||
1346 | struct device_node *np; | ||
1347 | |||
1348 | np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0); | ||
1349 | if (np) { | ||
1350 | struct platform_device *gangster = of_find_device_by_node(np); | ||
1351 | |||
1352 | dsi->slave = platform_get_drvdata(gangster); | ||
1353 | of_node_put(np); | ||
1354 | |||
1355 | if (!dsi->slave) | ||
1356 | return -EPROBE_DEFER; | ||
1357 | |||
1358 | dsi->slave->master = dsi; | ||
1359 | } | ||
1360 | |||
1361 | return 0; | ||
1362 | } | ||
1363 | |||
835 | static int tegra_dsi_probe(struct platform_device *pdev) | 1364 | static int tegra_dsi_probe(struct platform_device *pdev) |
836 | { | 1365 | { |
837 | struct tegra_dsi *dsi; | 1366 | struct tegra_dsi *dsi; |
@@ -843,11 +1372,19 @@ static int tegra_dsi_probe(struct platform_device *pdev) | |||
843 | return -ENOMEM; | 1372 | return -ENOMEM; |
844 | 1373 | ||
845 | dsi->output.dev = dsi->dev = &pdev->dev; | 1374 | dsi->output.dev = dsi->dev = &pdev->dev; |
1375 | dsi->video_fifo_depth = 1920; | ||
1376 | dsi->host_fifo_depth = 64; | ||
1377 | |||
1378 | err = tegra_dsi_ganged_probe(dsi); | ||
1379 | if (err < 0) | ||
1380 | return err; | ||
846 | 1381 | ||
847 | err = tegra_output_probe(&dsi->output); | 1382 | err = tegra_output_probe(&dsi->output); |
848 | if (err < 0) | 1383 | if (err < 0) |
849 | return err; | 1384 | return err; |
850 | 1385 | ||
1386 | dsi->output.connector.polled = DRM_CONNECTOR_POLL_HPD; | ||
1387 | |||
851 | /* | 1388 | /* |
852 | * Assume these values by default. When a DSI peripheral driver | 1389 | * Assume these values by default. When a DSI peripheral driver |
853 | * attaches to the DSI host, the parameters will be taken from | 1390 | * attaches to the DSI host, the parameters will be taken from |
@@ -861,68 +1398,83 @@ static int tegra_dsi_probe(struct platform_device *pdev) | |||
861 | if (IS_ERR(dsi->rst)) | 1398 | if (IS_ERR(dsi->rst)) |
862 | return PTR_ERR(dsi->rst); | 1399 | return PTR_ERR(dsi->rst); |
863 | 1400 | ||
1401 | err = reset_control_deassert(dsi->rst); | ||
1402 | if (err < 0) { | ||
1403 | dev_err(&pdev->dev, "failed to bring DSI out of reset: %d\n", | ||
1404 | err); | ||
1405 | return err; | ||
1406 | } | ||
1407 | |||
864 | dsi->clk = devm_clk_get(&pdev->dev, NULL); | 1408 | dsi->clk = devm_clk_get(&pdev->dev, NULL); |
865 | if (IS_ERR(dsi->clk)) { | 1409 | if (IS_ERR(dsi->clk)) { |
866 | dev_err(&pdev->dev, "cannot get DSI clock\n"); | 1410 | dev_err(&pdev->dev, "cannot get DSI clock\n"); |
867 | return PTR_ERR(dsi->clk); | 1411 | err = PTR_ERR(dsi->clk); |
1412 | goto reset; | ||
868 | } | 1413 | } |
869 | 1414 | ||
870 | err = clk_prepare_enable(dsi->clk); | 1415 | err = clk_prepare_enable(dsi->clk); |
871 | if (err < 0) { | 1416 | if (err < 0) { |
872 | dev_err(&pdev->dev, "cannot enable DSI clock\n"); | 1417 | dev_err(&pdev->dev, "cannot enable DSI clock\n"); |
873 | return err; | 1418 | goto reset; |
874 | } | 1419 | } |
875 | 1420 | ||
876 | dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); | 1421 | dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); |
877 | if (IS_ERR(dsi->clk_lp)) { | 1422 | if (IS_ERR(dsi->clk_lp)) { |
878 | dev_err(&pdev->dev, "cannot get low-power clock\n"); | 1423 | dev_err(&pdev->dev, "cannot get low-power clock\n"); |
879 | return PTR_ERR(dsi->clk_lp); | 1424 | err = PTR_ERR(dsi->clk_lp); |
1425 | goto disable_clk; | ||
880 | } | 1426 | } |
881 | 1427 | ||
882 | err = clk_prepare_enable(dsi->clk_lp); | 1428 | err = clk_prepare_enable(dsi->clk_lp); |
883 | if (err < 0) { | 1429 | if (err < 0) { |
884 | dev_err(&pdev->dev, "cannot enable low-power clock\n"); | 1430 | dev_err(&pdev->dev, "cannot enable low-power clock\n"); |
885 | return err; | 1431 | goto disable_clk; |
886 | } | 1432 | } |
887 | 1433 | ||
888 | dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); | 1434 | dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); |
889 | if (IS_ERR(dsi->clk_parent)) { | 1435 | if (IS_ERR(dsi->clk_parent)) { |
890 | dev_err(&pdev->dev, "cannot get parent clock\n"); | 1436 | dev_err(&pdev->dev, "cannot get parent clock\n"); |
891 | return PTR_ERR(dsi->clk_parent); | 1437 | err = PTR_ERR(dsi->clk_parent); |
892 | } | 1438 | goto disable_clk_lp; |
893 | |||
894 | err = clk_prepare_enable(dsi->clk_parent); | ||
895 | if (err < 0) { | ||
896 | dev_err(&pdev->dev, "cannot enable parent clock\n"); | ||
897 | return err; | ||
898 | } | 1439 | } |
899 | 1440 | ||
900 | dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); | 1441 | dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); |
901 | if (IS_ERR(dsi->vdd)) { | 1442 | if (IS_ERR(dsi->vdd)) { |
902 | dev_err(&pdev->dev, "cannot get VDD supply\n"); | 1443 | dev_err(&pdev->dev, "cannot get VDD supply\n"); |
903 | return PTR_ERR(dsi->vdd); | 1444 | err = PTR_ERR(dsi->vdd); |
1445 | goto disable_clk_lp; | ||
904 | } | 1446 | } |
905 | 1447 | ||
906 | err = regulator_enable(dsi->vdd); | 1448 | err = regulator_enable(dsi->vdd); |
907 | if (err < 0) { | 1449 | if (err < 0) { |
908 | dev_err(&pdev->dev, "cannot enable VDD supply\n"); | 1450 | dev_err(&pdev->dev, "cannot enable VDD supply\n"); |
909 | return err; | 1451 | goto disable_clk_lp; |
910 | } | 1452 | } |
911 | 1453 | ||
912 | err = tegra_dsi_setup_clocks(dsi); | 1454 | err = tegra_dsi_setup_clocks(dsi); |
913 | if (err < 0) { | 1455 | if (err < 0) { |
914 | dev_err(&pdev->dev, "cannot setup clocks\n"); | 1456 | dev_err(&pdev->dev, "cannot setup clocks\n"); |
915 | return err; | 1457 | goto disable_vdd; |
916 | } | 1458 | } |
917 | 1459 | ||
918 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1460 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
919 | dsi->regs = devm_ioremap_resource(&pdev->dev, regs); | 1461 | dsi->regs = devm_ioremap_resource(&pdev->dev, regs); |
920 | if (IS_ERR(dsi->regs)) | 1462 | if (IS_ERR(dsi->regs)) { |
921 | return PTR_ERR(dsi->regs); | 1463 | err = PTR_ERR(dsi->regs); |
1464 | goto disable_vdd; | ||
1465 | } | ||
922 | 1466 | ||
923 | dsi->mipi = tegra_mipi_request(&pdev->dev); | 1467 | dsi->mipi = tegra_mipi_request(&pdev->dev); |
924 | if (IS_ERR(dsi->mipi)) | 1468 | if (IS_ERR(dsi->mipi)) { |
925 | return PTR_ERR(dsi->mipi); | 1469 | err = PTR_ERR(dsi->mipi); |
1470 | goto disable_vdd; | ||
1471 | } | ||
1472 | |||
1473 | err = tegra_dsi_pad_calibrate(dsi); | ||
1474 | if (err < 0) { | ||
1475 | dev_err(dsi->dev, "MIPI calibration failed: %d\n", err); | ||
1476 | goto mipi_free; | ||
1477 | } | ||
926 | 1478 | ||
927 | dsi->host.ops = &tegra_dsi_host_ops; | 1479 | dsi->host.ops = &tegra_dsi_host_ops; |
928 | dsi->host.dev = &pdev->dev; | 1480 | dsi->host.dev = &pdev->dev; |
@@ -930,7 +1482,7 @@ static int tegra_dsi_probe(struct platform_device *pdev) | |||
930 | err = mipi_dsi_host_register(&dsi->host); | 1482 | err = mipi_dsi_host_register(&dsi->host); |
931 | if (err < 0) { | 1483 | if (err < 0) { |
932 | dev_err(&pdev->dev, "failed to register DSI host: %d\n", err); | 1484 | dev_err(&pdev->dev, "failed to register DSI host: %d\n", err); |
933 | return err; | 1485 | goto mipi_free; |
934 | } | 1486 | } |
935 | 1487 | ||
936 | INIT_LIST_HEAD(&dsi->client.list); | 1488 | INIT_LIST_HEAD(&dsi->client.list); |
@@ -941,12 +1493,26 @@ static int tegra_dsi_probe(struct platform_device *pdev) | |||
941 | if (err < 0) { | 1493 | if (err < 0) { |
942 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", | 1494 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", |
943 | err); | 1495 | err); |
944 | return err; | 1496 | goto unregister; |
945 | } | 1497 | } |
946 | 1498 | ||
947 | platform_set_drvdata(pdev, dsi); | 1499 | platform_set_drvdata(pdev, dsi); |
948 | 1500 | ||
949 | return 0; | 1501 | return 0; |
1502 | |||
1503 | unregister: | ||
1504 | mipi_dsi_host_unregister(&dsi->host); | ||
1505 | mipi_free: | ||
1506 | tegra_mipi_free(dsi->mipi); | ||
1507 | disable_vdd: | ||
1508 | regulator_disable(dsi->vdd); | ||
1509 | disable_clk_lp: | ||
1510 | clk_disable_unprepare(dsi->clk_lp); | ||
1511 | disable_clk: | ||
1512 | clk_disable_unprepare(dsi->clk); | ||
1513 | reset: | ||
1514 | reset_control_assert(dsi->rst); | ||
1515 | return err; | ||
950 | } | 1516 | } |
951 | 1517 | ||
952 | static int tegra_dsi_remove(struct platform_device *pdev) | 1518 | static int tegra_dsi_remove(struct platform_device *pdev) |
@@ -965,7 +1531,6 @@ static int tegra_dsi_remove(struct platform_device *pdev) | |||
965 | tegra_mipi_free(dsi->mipi); | 1531 | tegra_mipi_free(dsi->mipi); |
966 | 1532 | ||
967 | regulator_disable(dsi->vdd); | 1533 | regulator_disable(dsi->vdd); |
968 | clk_disable_unprepare(dsi->clk_parent); | ||
969 | clk_disable_unprepare(dsi->clk_lp); | 1534 | clk_disable_unprepare(dsi->clk_lp); |
970 | clk_disable_unprepare(dsi->clk); | 1535 | clk_disable_unprepare(dsi->clk); |
971 | reset_control_assert(dsi->rst); | 1536 | reset_control_assert(dsi->rst); |
diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h index 5ce610d08d77..bad1006a5150 100644 --- a/drivers/gpu/drm/tegra/dsi.h +++ b/drivers/gpu/drm/tegra/dsi.h | |||
@@ -21,9 +21,16 @@ | |||
21 | #define DSI_INT_STATUS 0x0d | 21 | #define DSI_INT_STATUS 0x0d |
22 | #define DSI_INT_MASK 0x0e | 22 | #define DSI_INT_MASK 0x0e |
23 | #define DSI_HOST_CONTROL 0x0f | 23 | #define DSI_HOST_CONTROL 0x0f |
24 | #define DSI_HOST_CONTROL_FIFO_RESET (1 << 21) | ||
25 | #define DSI_HOST_CONTROL_CRC_RESET (1 << 20) | ||
26 | #define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) | ||
27 | #define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) | ||
28 | #define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) | ||
24 | #define DSI_HOST_CONTROL_RAW (1 << 6) | 29 | #define DSI_HOST_CONTROL_RAW (1 << 6) |
25 | #define DSI_HOST_CONTROL_HS (1 << 5) | 30 | #define DSI_HOST_CONTROL_HS (1 << 5) |
26 | #define DSI_HOST_CONTROL_BTA (1 << 2) | 31 | #define DSI_HOST_CONTROL_FIFO_SEL (1 << 4) |
32 | #define DSI_HOST_CONTROL_IMM_BTA (1 << 3) | ||
33 | #define DSI_HOST_CONTROL_PKT_BTA (1 << 2) | ||
27 | #define DSI_HOST_CONTROL_CS (1 << 1) | 34 | #define DSI_HOST_CONTROL_CS (1 << 1) |
28 | #define DSI_HOST_CONTROL_ECC (1 << 0) | 35 | #define DSI_HOST_CONTROL_ECC (1 << 0) |
29 | #define DSI_CONTROL 0x10 | 36 | #define DSI_CONTROL 0x10 |
@@ -39,9 +46,13 @@ | |||
39 | #define DSI_SOL_DELAY 0x11 | 46 | #define DSI_SOL_DELAY 0x11 |
40 | #define DSI_MAX_THRESHOLD 0x12 | 47 | #define DSI_MAX_THRESHOLD 0x12 |
41 | #define DSI_TRIGGER 0x13 | 48 | #define DSI_TRIGGER 0x13 |
49 | #define DSI_TRIGGER_HOST (1 << 1) | ||
50 | #define DSI_TRIGGER_VIDEO (1 << 0) | ||
42 | #define DSI_TX_CRC 0x14 | 51 | #define DSI_TX_CRC 0x14 |
43 | #define DSI_STATUS 0x15 | 52 | #define DSI_STATUS 0x15 |
44 | #define DSI_STATUS_IDLE (1 << 10) | 53 | #define DSI_STATUS_IDLE (1 << 10) |
54 | #define DSI_STATUS_UNDERFLOW (1 << 9) | ||
55 | #define DSI_STATUS_OVERFLOW (1 << 8) | ||
45 | #define DSI_INIT_SEQ_CONTROL 0x1a | 56 | #define DSI_INIT_SEQ_CONTROL 0x1a |
46 | #define DSI_INIT_SEQ_DATA_0 0x1b | 57 | #define DSI_INIT_SEQ_DATA_0 0x1b |
47 | #define DSI_INIT_SEQ_DATA_1 0x1c | 58 | #define DSI_INIT_SEQ_DATA_1 0x1c |
@@ -104,6 +115,7 @@ | |||
104 | #define DSI_PAD_CONTROL_3 0x51 | 115 | #define DSI_PAD_CONTROL_3 0x51 |
105 | #define DSI_PAD_CONTROL_4 0x52 | 116 | #define DSI_PAD_CONTROL_4 0x52 |
106 | #define DSI_GANGED_MODE_CONTROL 0x53 | 117 | #define DSI_GANGED_MODE_CONTROL 0x53 |
118 | #define DSI_GANGED_MODE_CONTROL_ENABLE (1 << 0) | ||
107 | #define DSI_GANGED_MODE_START 0x54 | 119 | #define DSI_GANGED_MODE_START 0x54 |
108 | #define DSI_GANGED_MODE_SIZE 0x55 | 120 | #define DSI_GANGED_MODE_SIZE 0x55 |
109 | #define DSI_RAW_DATA_BYTE_COUNT 0x56 | 121 | #define DSI_RAW_DATA_BYTE_COUNT 0x56 |
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 3513d12d5aa1..e9c715d89261 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c | |||
@@ -65,8 +65,12 @@ static void tegra_fb_destroy(struct drm_framebuffer *framebuffer) | |||
65 | for (i = 0; i < fb->num_planes; i++) { | 65 | for (i = 0; i < fb->num_planes; i++) { |
66 | struct tegra_bo *bo = fb->planes[i]; | 66 | struct tegra_bo *bo = fb->planes[i]; |
67 | 67 | ||
68 | if (bo) | 68 | if (bo) { |
69 | if (bo->pages && bo->vaddr) | ||
70 | vunmap(bo->vaddr); | ||
71 | |||
69 | drm_gem_object_unreference_unlocked(&bo->gem); | 72 | drm_gem_object_unreference_unlocked(&bo->gem); |
73 | } | ||
70 | } | 74 | } |
71 | 75 | ||
72 | drm_framebuffer_cleanup(framebuffer); | 76 | drm_framebuffer_cleanup(framebuffer); |
@@ -223,14 +227,16 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, | |||
223 | info = framebuffer_alloc(0, drm->dev); | 227 | info = framebuffer_alloc(0, drm->dev); |
224 | if (!info) { | 228 | if (!info) { |
225 | dev_err(drm->dev, "failed to allocate framebuffer info\n"); | 229 | dev_err(drm->dev, "failed to allocate framebuffer info\n"); |
226 | tegra_bo_free_object(&bo->gem); | 230 | drm_gem_object_unreference_unlocked(&bo->gem); |
227 | return -ENOMEM; | 231 | return -ENOMEM; |
228 | } | 232 | } |
229 | 233 | ||
230 | fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1); | 234 | fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1); |
231 | if (IS_ERR(fbdev->fb)) { | 235 | if (IS_ERR(fbdev->fb)) { |
232 | dev_err(drm->dev, "failed to allocate DRM framebuffer\n"); | ||
233 | err = PTR_ERR(fbdev->fb); | 236 | err = PTR_ERR(fbdev->fb); |
237 | dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n", | ||
238 | err); | ||
239 | drm_gem_object_unreference_unlocked(&bo->gem); | ||
234 | goto release; | 240 | goto release; |
235 | } | 241 | } |
236 | 242 | ||
@@ -254,6 +260,16 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, | |||
254 | offset = info->var.xoffset * bytes_per_pixel + | 260 | offset = info->var.xoffset * bytes_per_pixel + |
255 | info->var.yoffset * fb->pitches[0]; | 261 | info->var.yoffset * fb->pitches[0]; |
256 | 262 | ||
263 | if (bo->pages) { | ||
264 | bo->vaddr = vmap(bo->pages, bo->num_pages, VM_MAP, | ||
265 | pgprot_writecombine(PAGE_KERNEL)); | ||
266 | if (!bo->vaddr) { | ||
267 | dev_err(drm->dev, "failed to vmap() framebuffer\n"); | ||
268 | err = -ENOMEM; | ||
269 | goto destroy; | ||
270 | } | ||
271 | } | ||
272 | |||
257 | drm->mode_config.fb_base = (resource_size_t)bo->paddr; | 273 | drm->mode_config.fb_base = (resource_size_t)bo->paddr; |
258 | info->screen_base = (void __iomem *)bo->vaddr + offset; | 274 | info->screen_base = (void __iomem *)bo->vaddr + offset; |
259 | info->screen_size = size; | 275 | info->screen_size = size; |
@@ -289,6 +305,11 @@ static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm) | |||
289 | return fbdev; | 305 | return fbdev; |
290 | } | 306 | } |
291 | 307 | ||
308 | static void tegra_fbdev_free(struct tegra_fbdev *fbdev) | ||
309 | { | ||
310 | kfree(fbdev); | ||
311 | } | ||
312 | |||
292 | static int tegra_fbdev_init(struct tegra_fbdev *fbdev, | 313 | static int tegra_fbdev_init(struct tegra_fbdev *fbdev, |
293 | unsigned int preferred_bpp, | 314 | unsigned int preferred_bpp, |
294 | unsigned int num_crtc, | 315 | unsigned int num_crtc, |
@@ -299,19 +320,21 @@ static int tegra_fbdev_init(struct tegra_fbdev *fbdev, | |||
299 | 320 | ||
300 | err = drm_fb_helper_init(drm, &fbdev->base, num_crtc, max_connectors); | 321 | err = drm_fb_helper_init(drm, &fbdev->base, num_crtc, max_connectors); |
301 | if (err < 0) { | 322 | if (err < 0) { |
302 | dev_err(drm->dev, "failed to initialize DRM FB helper\n"); | 323 | dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n", |
324 | err); | ||
303 | return err; | 325 | return err; |
304 | } | 326 | } |
305 | 327 | ||
306 | err = drm_fb_helper_single_add_all_connectors(&fbdev->base); | 328 | err = drm_fb_helper_single_add_all_connectors(&fbdev->base); |
307 | if (err < 0) { | 329 | if (err < 0) { |
308 | dev_err(drm->dev, "failed to add connectors\n"); | 330 | dev_err(drm->dev, "failed to add connectors: %d\n", err); |
309 | goto fini; | 331 | goto fini; |
310 | } | 332 | } |
311 | 333 | ||
312 | err = drm_fb_helper_initial_config(&fbdev->base, preferred_bpp); | 334 | err = drm_fb_helper_initial_config(&fbdev->base, preferred_bpp); |
313 | if (err < 0) { | 335 | if (err < 0) { |
314 | dev_err(drm->dev, "failed to set initial configuration\n"); | 336 | dev_err(drm->dev, "failed to set initial configuration: %d\n", |
337 | err); | ||
315 | goto fini; | 338 | goto fini; |
316 | } | 339 | } |
317 | 340 | ||
@@ -322,7 +345,7 @@ fini: | |||
322 | return err; | 345 | return err; |
323 | } | 346 | } |
324 | 347 | ||
325 | static void tegra_fbdev_free(struct tegra_fbdev *fbdev) | 348 | static void tegra_fbdev_exit(struct tegra_fbdev *fbdev) |
326 | { | 349 | { |
327 | struct fb_info *info = fbdev->base.fbdev; | 350 | struct fb_info *info = fbdev->base.fbdev; |
328 | 351 | ||
@@ -341,11 +364,11 @@ static void tegra_fbdev_free(struct tegra_fbdev *fbdev) | |||
341 | 364 | ||
342 | if (fbdev->fb) { | 365 | if (fbdev->fb) { |
343 | drm_framebuffer_unregister_private(&fbdev->fb->base); | 366 | drm_framebuffer_unregister_private(&fbdev->fb->base); |
344 | tegra_fb_destroy(&fbdev->fb->base); | 367 | drm_framebuffer_remove(&fbdev->fb->base); |
345 | } | 368 | } |
346 | 369 | ||
347 | drm_fb_helper_fini(&fbdev->base); | 370 | drm_fb_helper_fini(&fbdev->base); |
348 | kfree(fbdev); | 371 | tegra_fbdev_free(fbdev); |
349 | } | 372 | } |
350 | 373 | ||
351 | void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev) | 374 | void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev) |
@@ -393,6 +416,15 @@ int tegra_drm_fb_prepare(struct drm_device *drm) | |||
393 | return 0; | 416 | return 0; |
394 | } | 417 | } |
395 | 418 | ||
419 | void tegra_drm_fb_free(struct drm_device *drm) | ||
420 | { | ||
421 | #ifdef CONFIG_DRM_TEGRA_FBDEV | ||
422 | struct tegra_drm *tegra = drm->dev_private; | ||
423 | |||
424 | tegra_fbdev_free(tegra->fbdev); | ||
425 | #endif | ||
426 | } | ||
427 | |||
396 | int tegra_drm_fb_init(struct drm_device *drm) | 428 | int tegra_drm_fb_init(struct drm_device *drm) |
397 | { | 429 | { |
398 | #ifdef CONFIG_DRM_TEGRA_FBDEV | 430 | #ifdef CONFIG_DRM_TEGRA_FBDEV |
@@ -413,6 +445,6 @@ void tegra_drm_fb_exit(struct drm_device *drm) | |||
413 | #ifdef CONFIG_DRM_TEGRA_FBDEV | 445 | #ifdef CONFIG_DRM_TEGRA_FBDEV |
414 | struct tegra_drm *tegra = drm->dev_private; | 446 | struct tegra_drm *tegra = drm->dev_private; |
415 | 447 | ||
416 | tegra_fbdev_free(tegra->fbdev); | 448 | tegra_fbdev_exit(tegra->fbdev); |
417 | #endif | 449 | #endif |
418 | } | 450 | } |
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index ce023fa3e8ae..da32086cbeaf 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c | |||
@@ -14,6 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/dma-buf.h> | 16 | #include <linux/dma-buf.h> |
17 | #include <linux/iommu.h> | ||
17 | #include <drm/tegra_drm.h> | 18 | #include <drm/tegra_drm.h> |
18 | 19 | ||
19 | #include "drm.h" | 20 | #include "drm.h" |
@@ -91,13 +92,90 @@ static const struct host1x_bo_ops tegra_bo_ops = { | |||
91 | .kunmap = tegra_bo_kunmap, | 92 | .kunmap = tegra_bo_kunmap, |
92 | }; | 93 | }; |
93 | 94 | ||
94 | static void tegra_bo_destroy(struct drm_device *drm, struct tegra_bo *bo) | 95 | /* |
96 | * A generic iommu_map_sg() function is being reviewed and will hopefully be | ||
97 | * merged soon. At that point this function can be dropped in favour of the | ||
98 | * one provided by the IOMMU API. | ||
99 | */ | ||
100 | static ssize_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova, | ||
101 | struct scatterlist *sg, unsigned int nents, | ||
102 | int prot) | ||
95 | { | 103 | { |
96 | dma_free_writecombine(drm->dev, bo->gem.size, bo->vaddr, bo->paddr); | 104 | struct scatterlist *s; |
105 | size_t offset = 0; | ||
106 | unsigned int i; | ||
107 | int err; | ||
108 | |||
109 | for_each_sg(sg, s, nents, i) { | ||
110 | phys_addr_t phys = page_to_phys(sg_page(s)); | ||
111 | size_t length = s->offset + s->length; | ||
112 | |||
113 | err = iommu_map(domain, iova + offset, phys, length, prot); | ||
114 | if (err < 0) { | ||
115 | iommu_unmap(domain, iova, offset); | ||
116 | return err; | ||
117 | } | ||
118 | |||
119 | offset += length; | ||
120 | } | ||
121 | |||
122 | return offset; | ||
97 | } | 123 | } |
98 | 124 | ||
99 | struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size, | 125 | static int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo) |
100 | unsigned long flags) | 126 | { |
127 | int prot = IOMMU_READ | IOMMU_WRITE; | ||
128 | ssize_t err; | ||
129 | |||
130 | if (bo->mm) | ||
131 | return -EBUSY; | ||
132 | |||
133 | bo->mm = kzalloc(sizeof(*bo->mm), GFP_KERNEL); | ||
134 | if (!bo->mm) | ||
135 | return -ENOMEM; | ||
136 | |||
137 | err = drm_mm_insert_node_generic(&tegra->mm, bo->mm, bo->gem.size, | ||
138 | PAGE_SIZE, 0, 0, 0); | ||
139 | if (err < 0) { | ||
140 | dev_err(tegra->drm->dev, "out of I/O virtual memory: %zd\n", | ||
141 | err); | ||
142 | goto free; | ||
143 | } | ||
144 | |||
145 | bo->paddr = bo->mm->start; | ||
146 | |||
147 | err = __iommu_map_sg(tegra->domain, bo->paddr, bo->sgt->sgl, | ||
148 | bo->sgt->nents, prot); | ||
149 | if (err < 0) { | ||
150 | dev_err(tegra->drm->dev, "failed to map buffer: %zd\n", err); | ||
151 | goto remove; | ||
152 | } | ||
153 | |||
154 | bo->size = err; | ||
155 | |||
156 | return 0; | ||
157 | |||
158 | remove: | ||
159 | drm_mm_remove_node(bo->mm); | ||
160 | free: | ||
161 | kfree(bo->mm); | ||
162 | return err; | ||
163 | } | ||
164 | |||
165 | static int tegra_bo_iommu_unmap(struct tegra_drm *tegra, struct tegra_bo *bo) | ||
166 | { | ||
167 | if (!bo->mm) | ||
168 | return 0; | ||
169 | |||
170 | iommu_unmap(tegra->domain, bo->paddr, bo->size); | ||
171 | drm_mm_remove_node(bo->mm); | ||
172 | kfree(bo->mm); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static struct tegra_bo *tegra_bo_alloc_object(struct drm_device *drm, | ||
178 | size_t size) | ||
101 | { | 179 | { |
102 | struct tegra_bo *bo; | 180 | struct tegra_bo *bo; |
103 | int err; | 181 | int err; |
@@ -109,22 +187,96 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size, | |||
109 | host1x_bo_init(&bo->base, &tegra_bo_ops); | 187 | host1x_bo_init(&bo->base, &tegra_bo_ops); |
110 | size = round_up(size, PAGE_SIZE); | 188 | size = round_up(size, PAGE_SIZE); |
111 | 189 | ||
112 | bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr, | ||
113 | GFP_KERNEL | __GFP_NOWARN); | ||
114 | if (!bo->vaddr) { | ||
115 | dev_err(drm->dev, "failed to allocate buffer with size %u\n", | ||
116 | size); | ||
117 | err = -ENOMEM; | ||
118 | goto err_dma; | ||
119 | } | ||
120 | |||
121 | err = drm_gem_object_init(drm, &bo->gem, size); | 190 | err = drm_gem_object_init(drm, &bo->gem, size); |
122 | if (err) | 191 | if (err < 0) |
123 | goto err_init; | 192 | goto free; |
124 | 193 | ||
125 | err = drm_gem_create_mmap_offset(&bo->gem); | 194 | err = drm_gem_create_mmap_offset(&bo->gem); |
126 | if (err) | 195 | if (err < 0) |
127 | goto err_mmap; | 196 | goto release; |
197 | |||
198 | return bo; | ||
199 | |||
200 | release: | ||
201 | drm_gem_object_release(&bo->gem); | ||
202 | free: | ||
203 | kfree(bo); | ||
204 | return ERR_PTR(err); | ||
205 | } | ||
206 | |||
207 | static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) | ||
208 | { | ||
209 | if (bo->pages) { | ||
210 | drm_gem_put_pages(&bo->gem, bo->pages, true, true); | ||
211 | sg_free_table(bo->sgt); | ||
212 | kfree(bo->sgt); | ||
213 | } else if (bo->vaddr) { | ||
214 | dma_free_writecombine(drm->dev, bo->gem.size, bo->vaddr, | ||
215 | bo->paddr); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo, | ||
220 | size_t size) | ||
221 | { | ||
222 | bo->pages = drm_gem_get_pages(&bo->gem); | ||
223 | if (IS_ERR(bo->pages)) | ||
224 | return PTR_ERR(bo->pages); | ||
225 | |||
226 | bo->num_pages = size >> PAGE_SHIFT; | ||
227 | |||
228 | bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); | ||
229 | if (IS_ERR(bo->sgt)) { | ||
230 | drm_gem_put_pages(&bo->gem, bo->pages, false, false); | ||
231 | return PTR_ERR(bo->sgt); | ||
232 | } | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo, | ||
238 | size_t size) | ||
239 | { | ||
240 | struct tegra_drm *tegra = drm->dev_private; | ||
241 | int err; | ||
242 | |||
243 | if (tegra->domain) { | ||
244 | err = tegra_bo_get_pages(drm, bo, size); | ||
245 | if (err < 0) | ||
246 | return err; | ||
247 | |||
248 | err = tegra_bo_iommu_map(tegra, bo); | ||
249 | if (err < 0) { | ||
250 | tegra_bo_free(drm, bo); | ||
251 | return err; | ||
252 | } | ||
253 | } else { | ||
254 | bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr, | ||
255 | GFP_KERNEL | __GFP_NOWARN); | ||
256 | if (!bo->vaddr) { | ||
257 | dev_err(drm->dev, | ||
258 | "failed to allocate buffer of size %zu\n", | ||
259 | size); | ||
260 | return -ENOMEM; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | struct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size, | ||
268 | unsigned long flags) | ||
269 | { | ||
270 | struct tegra_bo *bo; | ||
271 | int err; | ||
272 | |||
273 | bo = tegra_bo_alloc_object(drm, size); | ||
274 | if (IS_ERR(bo)) | ||
275 | return bo; | ||
276 | |||
277 | err = tegra_bo_alloc(drm, bo, size); | ||
278 | if (err < 0) | ||
279 | goto release; | ||
128 | 280 | ||
129 | if (flags & DRM_TEGRA_GEM_CREATE_TILED) | 281 | if (flags & DRM_TEGRA_GEM_CREATE_TILED) |
130 | bo->tiling.mode = TEGRA_BO_TILING_MODE_TILED; | 282 | bo->tiling.mode = TEGRA_BO_TILING_MODE_TILED; |
@@ -134,69 +286,52 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size, | |||
134 | 286 | ||
135 | return bo; | 287 | return bo; |
136 | 288 | ||
137 | err_mmap: | 289 | release: |
138 | drm_gem_object_release(&bo->gem); | 290 | drm_gem_object_release(&bo->gem); |
139 | err_init: | ||
140 | tegra_bo_destroy(drm, bo); | ||
141 | err_dma: | ||
142 | kfree(bo); | 291 | kfree(bo); |
143 | |||
144 | return ERR_PTR(err); | 292 | return ERR_PTR(err); |
145 | } | 293 | } |
146 | 294 | ||
147 | struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, | 295 | struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, |
148 | struct drm_device *drm, | 296 | struct drm_device *drm, |
149 | unsigned int size, | 297 | size_t size, |
150 | unsigned long flags, | 298 | unsigned long flags, |
151 | unsigned int *handle) | 299 | u32 *handle) |
152 | { | 300 | { |
153 | struct tegra_bo *bo; | 301 | struct tegra_bo *bo; |
154 | int ret; | 302 | int err; |
155 | 303 | ||
156 | bo = tegra_bo_create(drm, size, flags); | 304 | bo = tegra_bo_create(drm, size, flags); |
157 | if (IS_ERR(bo)) | 305 | if (IS_ERR(bo)) |
158 | return bo; | 306 | return bo; |
159 | 307 | ||
160 | ret = drm_gem_handle_create(file, &bo->gem, handle); | 308 | err = drm_gem_handle_create(file, &bo->gem, handle); |
161 | if (ret) | 309 | if (err) { |
162 | goto err; | 310 | tegra_bo_free_object(&bo->gem); |
311 | return ERR_PTR(err); | ||
312 | } | ||
163 | 313 | ||
164 | drm_gem_object_unreference_unlocked(&bo->gem); | 314 | drm_gem_object_unreference_unlocked(&bo->gem); |
165 | 315 | ||
166 | return bo; | 316 | return bo; |
167 | |||
168 | err: | ||
169 | tegra_bo_free_object(&bo->gem); | ||
170 | return ERR_PTR(ret); | ||
171 | } | 317 | } |
172 | 318 | ||
173 | static struct tegra_bo *tegra_bo_import(struct drm_device *drm, | 319 | static struct tegra_bo *tegra_bo_import(struct drm_device *drm, |
174 | struct dma_buf *buf) | 320 | struct dma_buf *buf) |
175 | { | 321 | { |
322 | struct tegra_drm *tegra = drm->dev_private; | ||
176 | struct dma_buf_attachment *attach; | 323 | struct dma_buf_attachment *attach; |
177 | struct tegra_bo *bo; | 324 | struct tegra_bo *bo; |
178 | ssize_t size; | ||
179 | int err; | 325 | int err; |
180 | 326 | ||
181 | bo = kzalloc(sizeof(*bo), GFP_KERNEL); | 327 | bo = tegra_bo_alloc_object(drm, buf->size); |
182 | if (!bo) | 328 | if (IS_ERR(bo)) |
183 | return ERR_PTR(-ENOMEM); | 329 | return bo; |
184 | |||
185 | host1x_bo_init(&bo->base, &tegra_bo_ops); | ||
186 | size = round_up(buf->size, PAGE_SIZE); | ||
187 | |||
188 | err = drm_gem_object_init(drm, &bo->gem, size); | ||
189 | if (err < 0) | ||
190 | goto free; | ||
191 | |||
192 | err = drm_gem_create_mmap_offset(&bo->gem); | ||
193 | if (err < 0) | ||
194 | goto release; | ||
195 | 330 | ||
196 | attach = dma_buf_attach(buf, drm->dev); | 331 | attach = dma_buf_attach(buf, drm->dev); |
197 | if (IS_ERR(attach)) { | 332 | if (IS_ERR(attach)) { |
198 | err = PTR_ERR(attach); | 333 | err = PTR_ERR(attach); |
199 | goto free_mmap; | 334 | goto free; |
200 | } | 335 | } |
201 | 336 | ||
202 | get_dma_buf(buf); | 337 | get_dma_buf(buf); |
@@ -212,12 +347,19 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm, | |||
212 | goto detach; | 347 | goto detach; |
213 | } | 348 | } |
214 | 349 | ||
215 | if (bo->sgt->nents > 1) { | 350 | if (tegra->domain) { |
216 | err = -EINVAL; | 351 | err = tegra_bo_iommu_map(tegra, bo); |
217 | goto detach; | 352 | if (err < 0) |
353 | goto detach; | ||
354 | } else { | ||
355 | if (bo->sgt->nents > 1) { | ||
356 | err = -EINVAL; | ||
357 | goto detach; | ||
358 | } | ||
359 | |||
360 | bo->paddr = sg_dma_address(bo->sgt->sgl); | ||
218 | } | 361 | } |
219 | 362 | ||
220 | bo->paddr = sg_dma_address(bo->sgt->sgl); | ||
221 | bo->gem.import_attach = attach; | 363 | bo->gem.import_attach = attach; |
222 | 364 | ||
223 | return bo; | 365 | return bo; |
@@ -228,47 +370,41 @@ detach: | |||
228 | 370 | ||
229 | dma_buf_detach(buf, attach); | 371 | dma_buf_detach(buf, attach); |
230 | dma_buf_put(buf); | 372 | dma_buf_put(buf); |
231 | free_mmap: | ||
232 | drm_gem_free_mmap_offset(&bo->gem); | ||
233 | release: | ||
234 | drm_gem_object_release(&bo->gem); | ||
235 | free: | 373 | free: |
374 | drm_gem_object_release(&bo->gem); | ||
236 | kfree(bo); | 375 | kfree(bo); |
237 | |||
238 | return ERR_PTR(err); | 376 | return ERR_PTR(err); |
239 | } | 377 | } |
240 | 378 | ||
241 | void tegra_bo_free_object(struct drm_gem_object *gem) | 379 | void tegra_bo_free_object(struct drm_gem_object *gem) |
242 | { | 380 | { |
381 | struct tegra_drm *tegra = gem->dev->dev_private; | ||
243 | struct tegra_bo *bo = to_tegra_bo(gem); | 382 | struct tegra_bo *bo = to_tegra_bo(gem); |
244 | 383 | ||
384 | if (tegra->domain) | ||
385 | tegra_bo_iommu_unmap(tegra, bo); | ||
386 | |||
245 | if (gem->import_attach) { | 387 | if (gem->import_attach) { |
246 | dma_buf_unmap_attachment(gem->import_attach, bo->sgt, | 388 | dma_buf_unmap_attachment(gem->import_attach, bo->sgt, |
247 | DMA_TO_DEVICE); | 389 | DMA_TO_DEVICE); |
248 | drm_prime_gem_destroy(gem, NULL); | 390 | drm_prime_gem_destroy(gem, NULL); |
249 | } else { | 391 | } else { |
250 | tegra_bo_destroy(gem->dev, bo); | 392 | tegra_bo_free(gem->dev, bo); |
251 | } | 393 | } |
252 | 394 | ||
253 | drm_gem_free_mmap_offset(gem); | ||
254 | drm_gem_object_release(gem); | 395 | drm_gem_object_release(gem); |
255 | |||
256 | kfree(bo); | 396 | kfree(bo); |
257 | } | 397 | } |
258 | 398 | ||
259 | int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, | 399 | int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, |
260 | struct drm_mode_create_dumb *args) | 400 | struct drm_mode_create_dumb *args) |
261 | { | 401 | { |
262 | int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); | 402 | unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); |
263 | struct tegra_drm *tegra = drm->dev_private; | 403 | struct tegra_drm *tegra = drm->dev_private; |
264 | struct tegra_bo *bo; | 404 | struct tegra_bo *bo; |
265 | 405 | ||
266 | min_pitch = round_up(min_pitch, tegra->pitch_align); | 406 | args->pitch = round_up(min_pitch, tegra->pitch_align); |
267 | if (args->pitch < min_pitch) | 407 | args->size = args->pitch * args->height; |
268 | args->pitch = min_pitch; | ||
269 | |||
270 | if (args->size < args->pitch * args->height) | ||
271 | args->size = args->pitch * args->height; | ||
272 | 408 | ||
273 | bo = tegra_bo_create_with_handle(file, drm, args->size, 0, | 409 | bo = tegra_bo_create_with_handle(file, drm, args->size, 0, |
274 | &args->handle); | 410 | &args->handle); |
@@ -279,7 +415,7 @@ int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, | |||
279 | } | 415 | } |
280 | 416 | ||
281 | int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, | 417 | int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, |
282 | uint32_t handle, uint64_t *offset) | 418 | u32 handle, u64 *offset) |
283 | { | 419 | { |
284 | struct drm_gem_object *gem; | 420 | struct drm_gem_object *gem; |
285 | struct tegra_bo *bo; | 421 | struct tegra_bo *bo; |
@@ -304,7 +440,38 @@ int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, | |||
304 | return 0; | 440 | return 0; |
305 | } | 441 | } |
306 | 442 | ||
443 | static int tegra_bo_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
444 | { | ||
445 | struct drm_gem_object *gem = vma->vm_private_data; | ||
446 | struct tegra_bo *bo = to_tegra_bo(gem); | ||
447 | struct page *page; | ||
448 | pgoff_t offset; | ||
449 | int err; | ||
450 | |||
451 | if (!bo->pages) | ||
452 | return VM_FAULT_SIGBUS; | ||
453 | |||
454 | offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; | ||
455 | page = bo->pages[offset]; | ||
456 | |||
457 | err = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page); | ||
458 | switch (err) { | ||
459 | case -EAGAIN: | ||
460 | case 0: | ||
461 | case -ERESTARTSYS: | ||
462 | case -EINTR: | ||
463 | case -EBUSY: | ||
464 | return VM_FAULT_NOPAGE; | ||
465 | |||
466 | case -ENOMEM: | ||
467 | return VM_FAULT_OOM; | ||
468 | } | ||
469 | |||
470 | return VM_FAULT_SIGBUS; | ||
471 | } | ||
472 | |||
307 | const struct vm_operations_struct tegra_bo_vm_ops = { | 473 | const struct vm_operations_struct tegra_bo_vm_ops = { |
474 | .fault = tegra_bo_fault, | ||
308 | .open = drm_gem_vm_open, | 475 | .open = drm_gem_vm_open, |
309 | .close = drm_gem_vm_close, | 476 | .close = drm_gem_vm_close, |
310 | }; | 477 | }; |
@@ -322,12 +489,30 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) | |||
322 | gem = vma->vm_private_data; | 489 | gem = vma->vm_private_data; |
323 | bo = to_tegra_bo(gem); | 490 | bo = to_tegra_bo(gem); |
324 | 491 | ||
325 | ret = remap_pfn_range(vma, vma->vm_start, bo->paddr >> PAGE_SHIFT, | 492 | if (!bo->pages) { |
326 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | 493 | unsigned long vm_pgoff = vma->vm_pgoff; |
327 | if (ret) | 494 | |
328 | drm_gem_vm_close(vma); | 495 | vma->vm_flags &= ~VM_PFNMAP; |
496 | vma->vm_pgoff = 0; | ||
497 | |||
498 | ret = dma_mmap_writecombine(gem->dev->dev, vma, bo->vaddr, | ||
499 | bo->paddr, gem->size); | ||
500 | if (ret) { | ||
501 | drm_gem_vm_close(vma); | ||
502 | return ret; | ||
503 | } | ||
504 | |||
505 | vma->vm_pgoff = vm_pgoff; | ||
506 | } else { | ||
507 | pgprot_t prot = vm_get_page_prot(vma->vm_flags); | ||
508 | |||
509 | vma->vm_flags |= VM_MIXEDMAP; | ||
510 | vma->vm_flags &= ~VM_PFNMAP; | ||
329 | 511 | ||
330 | return ret; | 512 | vma->vm_page_prot = pgprot_writecombine(prot); |
513 | } | ||
514 | |||
515 | return 0; | ||
331 | } | 516 | } |
332 | 517 | ||
333 | static struct sg_table * | 518 | static struct sg_table * |
@@ -342,21 +527,44 @@ tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, | |||
342 | if (!sgt) | 527 | if (!sgt) |
343 | return NULL; | 528 | return NULL; |
344 | 529 | ||
345 | if (sg_alloc_table(sgt, 1, GFP_KERNEL)) { | 530 | if (bo->pages) { |
346 | kfree(sgt); | 531 | struct scatterlist *sg; |
347 | return NULL; | 532 | unsigned int i; |
348 | } | ||
349 | 533 | ||
350 | sg_dma_address(sgt->sgl) = bo->paddr; | 534 | if (sg_alloc_table(sgt, bo->num_pages, GFP_KERNEL)) |
351 | sg_dma_len(sgt->sgl) = gem->size; | 535 | goto free; |
536 | |||
537 | for_each_sg(sgt->sgl, sg, bo->num_pages, i) | ||
538 | sg_set_page(sg, bo->pages[i], PAGE_SIZE, 0); | ||
539 | |||
540 | if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) | ||
541 | goto free; | ||
542 | } else { | ||
543 | if (sg_alloc_table(sgt, 1, GFP_KERNEL)) | ||
544 | goto free; | ||
545 | |||
546 | sg_dma_address(sgt->sgl) = bo->paddr; | ||
547 | sg_dma_len(sgt->sgl) = gem->size; | ||
548 | } | ||
352 | 549 | ||
353 | return sgt; | 550 | return sgt; |
551 | |||
552 | free: | ||
553 | sg_free_table(sgt); | ||
554 | kfree(sgt); | ||
555 | return NULL; | ||
354 | } | 556 | } |
355 | 557 | ||
356 | static void tegra_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, | 558 | static void tegra_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, |
357 | struct sg_table *sgt, | 559 | struct sg_table *sgt, |
358 | enum dma_data_direction dir) | 560 | enum dma_data_direction dir) |
359 | { | 561 | { |
562 | struct drm_gem_object *gem = attach->dmabuf->priv; | ||
563 | struct tegra_bo *bo = to_tegra_bo(gem); | ||
564 | |||
565 | if (bo->pages) | ||
566 | dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir); | ||
567 | |||
360 | sg_free_table(sgt); | 568 | sg_free_table(sgt); |
361 | kfree(sgt); | 569 | kfree(sgt); |
362 | } | 570 | } |
diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index 6538b56780c2..6c5f12ac0087 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h | |||
@@ -38,6 +38,12 @@ struct tegra_bo { | |||
38 | dma_addr_t paddr; | 38 | dma_addr_t paddr; |
39 | void *vaddr; | 39 | void *vaddr; |
40 | 40 | ||
41 | struct drm_mm_node *mm; | ||
42 | unsigned long num_pages; | ||
43 | struct page **pages; | ||
44 | /* size of IOMMU mapping */ | ||
45 | size_t size; | ||
46 | |||
41 | struct tegra_bo_tiling tiling; | 47 | struct tegra_bo_tiling tiling; |
42 | }; | 48 | }; |
43 | 49 | ||
@@ -46,18 +52,18 @@ static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem) | |||
46 | return container_of(gem, struct tegra_bo, gem); | 52 | return container_of(gem, struct tegra_bo, gem); |
47 | } | 53 | } |
48 | 54 | ||
49 | struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size, | 55 | struct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size, |
50 | unsigned long flags); | 56 | unsigned long flags); |
51 | struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, | 57 | struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, |
52 | struct drm_device *drm, | 58 | struct drm_device *drm, |
53 | unsigned int size, | 59 | size_t size, |
54 | unsigned long flags, | 60 | unsigned long flags, |
55 | unsigned int *handle); | 61 | u32 *handle); |
56 | void tegra_bo_free_object(struct drm_gem_object *gem); | 62 | void tegra_bo_free_object(struct drm_gem_object *gem); |
57 | int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, | 63 | int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, |
58 | struct drm_mode_create_dumb *args); | 64 | struct drm_mode_create_dumb *args); |
59 | int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, | 65 | int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, |
60 | uint32_t handle, uint64_t *offset); | 66 | u32 handle, u64 *offset); |
61 | 67 | ||
62 | int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); | 68 | int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); |
63 | 69 | ||
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 0c67d7eebc94..6a5c7b81fbc5 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c | |||
@@ -157,22 +157,18 @@ static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder, | |||
157 | 157 | ||
158 | static void tegra_encoder_prepare(struct drm_encoder *encoder) | 158 | static void tegra_encoder_prepare(struct drm_encoder *encoder) |
159 | { | 159 | { |
160 | tegra_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); | ||
160 | } | 161 | } |
161 | 162 | ||
162 | static void tegra_encoder_commit(struct drm_encoder *encoder) | 163 | static void tegra_encoder_commit(struct drm_encoder *encoder) |
163 | { | 164 | { |
165 | tegra_encoder_dpms(encoder, DRM_MODE_DPMS_ON); | ||
164 | } | 166 | } |
165 | 167 | ||
166 | static void tegra_encoder_mode_set(struct drm_encoder *encoder, | 168 | static void tegra_encoder_mode_set(struct drm_encoder *encoder, |
167 | struct drm_display_mode *mode, | 169 | struct drm_display_mode *mode, |
168 | struct drm_display_mode *adjusted) | 170 | struct drm_display_mode *adjusted) |
169 | { | 171 | { |
170 | struct tegra_output *output = encoder_to_output(encoder); | ||
171 | int err; | ||
172 | |||
173 | err = tegra_output_enable(output); | ||
174 | if (err < 0) | ||
175 | dev_err(encoder->dev->dev, "tegra_output_enable(): %d\n", err); | ||
176 | } | 172 | } |
177 | 173 | ||
178 | static const struct drm_encoder_helper_funcs encoder_helper_funcs = { | 174 | static const struct drm_encoder_helper_funcs encoder_helper_funcs = { |
@@ -187,7 +183,8 @@ static irqreturn_t hpd_irq(int irq, void *data) | |||
187 | { | 183 | { |
188 | struct tegra_output *output = data; | 184 | struct tegra_output *output = data; |
189 | 185 | ||
190 | drm_helper_hpd_irq_event(output->connector.dev); | 186 | if (output->connector.dev) |
187 | drm_helper_hpd_irq_event(output->connector.dev); | ||
191 | 188 | ||
192 | return IRQ_HANDLED; | 189 | return IRQ_HANDLED; |
193 | } | 190 | } |
@@ -259,6 +256,13 @@ int tegra_output_probe(struct tegra_output *output) | |||
259 | } | 256 | } |
260 | 257 | ||
261 | output->connector.polled = DRM_CONNECTOR_POLL_HPD; | 258 | output->connector.polled = DRM_CONNECTOR_POLL_HPD; |
259 | |||
260 | /* | ||
261 | * Disable the interrupt until the connector has been | ||
262 | * initialized to avoid a race in the hotplug interrupt | ||
263 | * handler. | ||
264 | */ | ||
265 | disable_irq(output->hpd_irq); | ||
262 | } | 266 | } |
263 | 267 | ||
264 | return 0; | 268 | return 0; |
@@ -324,10 +328,27 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output) | |||
324 | 328 | ||
325 | output->encoder.possible_crtcs = 0x3; | 329 | output->encoder.possible_crtcs = 0x3; |
326 | 330 | ||
331 | /* | ||
332 | * The connector is now registered and ready to receive hotplug events | ||
333 | * so the hotplug interrupt can be enabled. | ||
334 | */ | ||
335 | if (gpio_is_valid(output->hpd_gpio)) | ||
336 | enable_irq(output->hpd_irq); | ||
337 | |||
327 | return 0; | 338 | return 0; |
328 | } | 339 | } |
329 | 340 | ||
330 | int tegra_output_exit(struct tegra_output *output) | 341 | int tegra_output_exit(struct tegra_output *output) |
331 | { | 342 | { |
343 | /* | ||
344 | * The connector is going away, so the interrupt must be disabled to | ||
345 | * prevent the hotplug interrupt handler from potentially crashing. | ||
346 | */ | ||
347 | if (gpio_is_valid(output->hpd_gpio)) | ||
348 | disable_irq(output->hpd_irq); | ||
349 | |||
350 | if (output->panel) | ||
351 | drm_panel_detach(output->panel); | ||
352 | |||
332 | return 0; | 353 | return 0; |
333 | } | 354 | } |
diff --git a/drivers/gpu/host1x/cdma.c b/drivers/gpu/host1x/cdma.c index 3995255b16c7..5a8c8d55317a 100644 --- a/drivers/gpu/host1x/cdma.c +++ b/drivers/gpu/host1x/cdma.c | |||
@@ -97,7 +97,7 @@ fail: | |||
97 | static void host1x_pushbuffer_push(struct push_buffer *pb, u32 op1, u32 op2) | 97 | static void host1x_pushbuffer_push(struct push_buffer *pb, u32 op1, u32 op2) |
98 | { | 98 | { |
99 | u32 pos = pb->pos; | 99 | u32 pos = pb->pos; |
100 | u32 *p = (u32 *)((u32)pb->mapped + pos); | 100 | u32 *p = (u32 *)((void *)pb->mapped + pos); |
101 | WARN_ON(pos == pb->fence); | 101 | WARN_ON(pos == pb->fence); |
102 | *(p++) = op1; | 102 | *(p++) = op1; |
103 | *(p++) = op2; | 103 | *(p++) = op2; |
diff --git a/drivers/gpu/host1x/cdma.h b/drivers/gpu/host1x/cdma.h index 313c4b784348..470087af8fe5 100644 --- a/drivers/gpu/host1x/cdma.h +++ b/drivers/gpu/host1x/cdma.h | |||
@@ -42,7 +42,7 @@ struct host1x_job; | |||
42 | */ | 42 | */ |
43 | 43 | ||
44 | struct push_buffer { | 44 | struct push_buffer { |
45 | u32 *mapped; /* mapped pushbuffer memory */ | 45 | void *mapped; /* mapped pushbuffer memory */ |
46 | dma_addr_t phys; /* physical address of pushbuffer */ | 46 | dma_addr_t phys; /* physical address of pushbuffer */ |
47 | u32 fence; /* index we've written */ | 47 | u32 fence; /* index we've written */ |
48 | u32 pos; /* index to write to */ | 48 | u32 pos; /* index to write to */ |
diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c index 6b09b71940c2..305ea8f3382d 100644 --- a/drivers/gpu/host1x/hw/cdma_hw.c +++ b/drivers/gpu/host1x/hw/cdma_hw.c | |||
@@ -26,11 +26,11 @@ | |||
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 memory |
30 | */ | 30 | */ |
31 | static void push_buffer_init(struct push_buffer *pb) | 31 | static void push_buffer_init(struct push_buffer *pb) |
32 | { | 32 | { |
33 | *(pb->mapped + (pb->size_bytes >> 2)) = host1x_opcode_restart(0); | 33 | *(u32 *)(pb->mapped + pb->size_bytes) = host1x_opcode_restart(0); |
34 | } | 34 | } |
35 | 35 | ||
36 | /* | 36 | /* |
@@ -51,11 +51,11 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr, | |||
51 | 51 | ||
52 | /* NOP all the PB slots */ | 52 | /* NOP all the PB slots */ |
53 | while (nr_slots--) { | 53 | while (nr_slots--) { |
54 | u32 *p = (u32 *)((u32)pb->mapped + getptr); | 54 | u32 *p = (u32 *)(pb->mapped + getptr); |
55 | *(p++) = HOST1X_OPCODE_NOP; | 55 | *(p++) = HOST1X_OPCODE_NOP; |
56 | *(p++) = HOST1X_OPCODE_NOP; | 56 | *(p++) = HOST1X_OPCODE_NOP; |
57 | dev_dbg(host1x->dev, "%s: NOP at %#llx\n", __func__, | 57 | dev_dbg(host1x->dev, "%s: NOP at %pad+%#x\n", __func__, |
58 | (u64)pb->phys + getptr); | 58 | &pb->phys, getptr); |
59 | getptr = (getptr + 8) & (pb->size_bytes - 1); | 59 | getptr = (getptr + 8) & (pb->size_bytes - 1); |
60 | } | 60 | } |
61 | wmb(); | 61 | wmb(); |
diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c index 4608257ab656..946c332c3906 100644 --- a/drivers/gpu/host1x/hw/channel_hw.c +++ b/drivers/gpu/host1x/hw/channel_hw.c | |||
@@ -32,6 +32,7 @@ | |||
32 | static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo, | 32 | static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo, |
33 | u32 offset, u32 words) | 33 | u32 offset, u32 words) |
34 | { | 34 | { |
35 | struct device *dev = cdma_to_channel(cdma)->dev; | ||
35 | void *mem = NULL; | 36 | void *mem = NULL; |
36 | 37 | ||
37 | if (host1x_debug_trace_cmdbuf) | 38 | if (host1x_debug_trace_cmdbuf) |
@@ -44,11 +45,14 @@ static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo, | |||
44 | * of how much you can output to ftrace at once. | 45 | * of how much you can output to ftrace at once. |
45 | */ | 46 | */ |
46 | for (i = 0; i < words; i += TRACE_MAX_LENGTH) { | 47 | for (i = 0; i < words; i += TRACE_MAX_LENGTH) { |
47 | trace_host1x_cdma_push_gather( | 48 | u32 num_words = min(words - i, TRACE_MAX_LENGTH); |
48 | dev_name(cdma_to_channel(cdma)->dev), | 49 | offset += i * sizeof(u32); |
49 | (u32)bo, min(words - i, TRACE_MAX_LENGTH), | 50 | |
50 | offset + i * sizeof(u32), mem); | 51 | trace_host1x_cdma_push_gather(dev_name(dev), bo, |
52 | num_words, offset, | ||
53 | mem); | ||
51 | } | 54 | } |
55 | |||
52 | host1x_bo_munmap(bo, mem); | 56 | host1x_bo_munmap(bo, mem); |
53 | } | 57 | } |
54 | } | 58 | } |
diff --git a/drivers/gpu/host1x/hw/debug_hw.c b/drivers/gpu/host1x/hw/debug_hw.c index f72c873eff81..791de9351eeb 100644 --- a/drivers/gpu/host1x/hw/debug_hw.c +++ b/drivers/gpu/host1x/hw/debug_hw.c | |||
@@ -163,8 +163,8 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) | |||
163 | continue; | 163 | continue; |
164 | } | 164 | } |
165 | 165 | ||
166 | host1x_debug_output(o, " GATHER at %#llx+%04x, %d words\n", | 166 | host1x_debug_output(o, " GATHER at %pad+%#x, %d words\n", |
167 | (u64)g->base, g->offset, g->words); | 167 | &g->base, g->offset, g->words); |
168 | 168 | ||
169 | show_gather(o, g->base + g->offset, g->words, cdma, | 169 | show_gather(o, g->base + g->offset, g->words, cdma, |
170 | g->base, mapped); | 170 | g->base, mapped); |
diff --git a/drivers/gpu/host1x/job.h b/drivers/gpu/host1x/job.h index 33a697d6dcef..8b3c15df0660 100644 --- a/drivers/gpu/host1x/job.h +++ b/drivers/gpu/host1x/job.h | |||
@@ -23,7 +23,7 @@ struct host1x_job_gather { | |||
23 | u32 words; | 23 | u32 words; |
24 | dma_addr_t base; | 24 | dma_addr_t base; |
25 | struct host1x_bo *bo; | 25 | struct host1x_bo *bo; |
26 | int offset; | 26 | u32 offset; |
27 | bool handled; | 27 | bool handled; |
28 | }; | 28 | }; |
29 | 29 | ||
diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c index 9882ea122024..fbc6ee6ca337 100644 --- a/drivers/gpu/host1x/mipi.c +++ b/drivers/gpu/host1x/mipi.c | |||
@@ -49,35 +49,47 @@ | |||
49 | #define MIPI_CAL_CONFIG_DSIC 0x10 | 49 | #define MIPI_CAL_CONFIG_DSIC 0x10 |
50 | #define MIPI_CAL_CONFIG_DSID 0x11 | 50 | #define MIPI_CAL_CONFIG_DSID 0x11 |
51 | 51 | ||
52 | #define MIPI_CAL_CONFIG_DSIAB_CLK 0x19 | ||
53 | #define MIPI_CAL_CONFIG_DSICD_CLK 0x1a | ||
54 | #define MIPI_CAL_CONFIG_CSIAB_CLK 0x1b | ||
55 | #define MIPI_CAL_CONFIG_CSICD_CLK 0x1c | ||
56 | #define MIPI_CAL_CONFIG_CSIE_CLK 0x1d | ||
57 | |||
58 | /* for data and clock lanes */ | ||
52 | #define MIPI_CAL_CONFIG_SELECT (1 << 21) | 59 | #define MIPI_CAL_CONFIG_SELECT (1 << 21) |
60 | |||
61 | /* for data lanes */ | ||
53 | #define MIPI_CAL_CONFIG_HSPDOS(x) (((x) & 0x1f) << 16) | 62 | #define MIPI_CAL_CONFIG_HSPDOS(x) (((x) & 0x1f) << 16) |
54 | #define MIPI_CAL_CONFIG_HSPUOS(x) (((x) & 0x1f) << 8) | 63 | #define MIPI_CAL_CONFIG_HSPUOS(x) (((x) & 0x1f) << 8) |
55 | #define MIPI_CAL_CONFIG_TERMOS(x) (((x) & 0x1f) << 0) | 64 | #define MIPI_CAL_CONFIG_TERMOS(x) (((x) & 0x1f) << 0) |
56 | 65 | ||
66 | /* for clock lanes */ | ||
67 | #define MIPI_CAL_CONFIG_HSCLKPDOSD(x) (((x) & 0x1f) << 8) | ||
68 | #define MIPI_CAL_CONFIG_HSCLKPUOSD(x) (((x) & 0x1f) << 0) | ||
69 | |||
57 | #define MIPI_CAL_BIAS_PAD_CFG0 0x16 | 70 | #define MIPI_CAL_BIAS_PAD_CFG0 0x16 |
58 | #define MIPI_CAL_BIAS_PAD_PDVCLAMP (1 << 1) | 71 | #define MIPI_CAL_BIAS_PAD_PDVCLAMP (1 << 1) |
59 | #define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0) | 72 | #define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0) |
60 | 73 | ||
61 | #define MIPI_CAL_BIAS_PAD_CFG1 0x17 | 74 | #define MIPI_CAL_BIAS_PAD_CFG1 0x17 |
75 | #define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16) | ||
62 | 76 | ||
63 | #define MIPI_CAL_BIAS_PAD_CFG2 0x18 | 77 | #define MIPI_CAL_BIAS_PAD_CFG2 0x18 |
64 | #define MIPI_CAL_BIAS_PAD_PDVREG (1 << 1) | 78 | #define MIPI_CAL_BIAS_PAD_PDVREG (1 << 1) |
65 | 79 | ||
66 | static const struct module { | 80 | struct tegra_mipi_pad { |
67 | unsigned long reg; | 81 | unsigned long data; |
68 | } modules[] = { | 82 | unsigned long clk; |
69 | { .reg = MIPI_CAL_CONFIG_CSIA }, | 83 | }; |
70 | { .reg = MIPI_CAL_CONFIG_CSIB }, | 84 | |
71 | { .reg = MIPI_CAL_CONFIG_CSIC }, | 85 | struct tegra_mipi_soc { |
72 | { .reg = MIPI_CAL_CONFIG_CSID }, | 86 | bool has_clk_lane; |
73 | { .reg = MIPI_CAL_CONFIG_CSIE }, | 87 | const struct tegra_mipi_pad *pads; |
74 | { .reg = MIPI_CAL_CONFIG_DSIA }, | 88 | unsigned int num_pads; |
75 | { .reg = MIPI_CAL_CONFIG_DSIB }, | ||
76 | { .reg = MIPI_CAL_CONFIG_DSIC }, | ||
77 | { .reg = MIPI_CAL_CONFIG_DSID }, | ||
78 | }; | 89 | }; |
79 | 90 | ||
80 | struct tegra_mipi { | 91 | struct tegra_mipi { |
92 | const struct tegra_mipi_soc *soc; | ||
81 | void __iomem *regs; | 93 | void __iomem *regs; |
82 | struct mutex lock; | 94 | struct mutex lock; |
83 | struct clk *clk; | 95 | struct clk *clk; |
@@ -90,16 +102,16 @@ struct tegra_mipi_device { | |||
90 | unsigned long pads; | 102 | unsigned long pads; |
91 | }; | 103 | }; |
92 | 104 | ||
93 | static inline unsigned long tegra_mipi_readl(struct tegra_mipi *mipi, | 105 | static inline u32 tegra_mipi_readl(struct tegra_mipi *mipi, |
94 | unsigned long reg) | 106 | unsigned long offset) |
95 | { | 107 | { |
96 | return readl(mipi->regs + (reg << 2)); | 108 | return readl(mipi->regs + (offset << 2)); |
97 | } | 109 | } |
98 | 110 | ||
99 | static inline void tegra_mipi_writel(struct tegra_mipi *mipi, | 111 | static inline void tegra_mipi_writel(struct tegra_mipi *mipi, u32 value, |
100 | unsigned long value, unsigned long reg) | 112 | unsigned long offset) |
101 | { | 113 | { |
102 | writel(value, mipi->regs + (reg << 2)); | 114 | writel(value, mipi->regs + (offset << 2)); |
103 | } | 115 | } |
104 | 116 | ||
105 | struct tegra_mipi_device *tegra_mipi_request(struct device *device) | 117 | struct tegra_mipi_device *tegra_mipi_request(struct device *device) |
@@ -117,36 +129,35 @@ struct tegra_mipi_device *tegra_mipi_request(struct device *device) | |||
117 | 129 | ||
118 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 130 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
119 | if (!dev) { | 131 | if (!dev) { |
120 | of_node_put(args.np); | ||
121 | err = -ENOMEM; | 132 | err = -ENOMEM; |
122 | goto out; | 133 | goto out; |
123 | } | 134 | } |
124 | 135 | ||
125 | dev->pdev = of_find_device_by_node(args.np); | 136 | dev->pdev = of_find_device_by_node(args.np); |
126 | if (!dev->pdev) { | 137 | if (!dev->pdev) { |
127 | of_node_put(args.np); | ||
128 | err = -ENODEV; | 138 | err = -ENODEV; |
129 | goto free; | 139 | goto free; |
130 | } | 140 | } |
131 | 141 | ||
132 | of_node_put(args.np); | ||
133 | |||
134 | dev->mipi = platform_get_drvdata(dev->pdev); | 142 | dev->mipi = platform_get_drvdata(dev->pdev); |
135 | if (!dev->mipi) { | 143 | if (!dev->mipi) { |
136 | err = -EPROBE_DEFER; | 144 | err = -EPROBE_DEFER; |
137 | goto pdev_put; | 145 | goto put; |
138 | } | 146 | } |
139 | 147 | ||
148 | of_node_put(args.np); | ||
149 | |||
140 | dev->pads = args.args[0]; | 150 | dev->pads = args.args[0]; |
141 | dev->device = device; | 151 | dev->device = device; |
142 | 152 | ||
143 | return dev; | 153 | return dev; |
144 | 154 | ||
145 | pdev_put: | 155 | put: |
146 | platform_device_put(dev->pdev); | 156 | platform_device_put(dev->pdev); |
147 | free: | 157 | free: |
148 | kfree(dev); | 158 | kfree(dev); |
149 | out: | 159 | out: |
160 | of_node_put(args.np); | ||
150 | return ERR_PTR(err); | 161 | return ERR_PTR(err); |
151 | } | 162 | } |
152 | EXPORT_SYMBOL(tegra_mipi_request); | 163 | EXPORT_SYMBOL(tegra_mipi_request); |
@@ -161,7 +172,7 @@ EXPORT_SYMBOL(tegra_mipi_free); | |||
161 | static int tegra_mipi_wait(struct tegra_mipi *mipi) | 172 | static int tegra_mipi_wait(struct tegra_mipi *mipi) |
162 | { | 173 | { |
163 | unsigned long timeout = jiffies + msecs_to_jiffies(250); | 174 | unsigned long timeout = jiffies + msecs_to_jiffies(250); |
164 | unsigned long value; | 175 | u32 value; |
165 | 176 | ||
166 | while (time_before(jiffies, timeout)) { | 177 | while (time_before(jiffies, timeout)) { |
167 | value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS); | 178 | value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS); |
@@ -177,8 +188,9 @@ static int tegra_mipi_wait(struct tegra_mipi *mipi) | |||
177 | 188 | ||
178 | int tegra_mipi_calibrate(struct tegra_mipi_device *device) | 189 | int tegra_mipi_calibrate(struct tegra_mipi_device *device) |
179 | { | 190 | { |
180 | unsigned long value; | 191 | const struct tegra_mipi_soc *soc = device->mipi->soc; |
181 | unsigned int i; | 192 | unsigned int i; |
193 | u32 value; | ||
182 | int err; | 194 | int err; |
183 | 195 | ||
184 | err = clk_enable(device->mipi->clk); | 196 | err = clk_enable(device->mipi->clk); |
@@ -192,23 +204,35 @@ int tegra_mipi_calibrate(struct tegra_mipi_device *device) | |||
192 | value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; | 204 | value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; |
193 | tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0); | 205 | tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0); |
194 | 206 | ||
207 | tegra_mipi_writel(device->mipi, MIPI_CAL_BIAS_PAD_DRV_DN_REF(2), | ||
208 | MIPI_CAL_BIAS_PAD_CFG1); | ||
209 | |||
195 | value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2); | 210 | value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2); |
196 | value &= ~MIPI_CAL_BIAS_PAD_PDVREG; | 211 | value &= ~MIPI_CAL_BIAS_PAD_PDVREG; |
197 | tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2); | 212 | tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2); |
198 | 213 | ||
199 | for (i = 0; i < ARRAY_SIZE(modules); i++) { | 214 | for (i = 0; i < soc->num_pads; i++) { |
200 | if (device->pads & BIT(i)) | 215 | u32 clk = 0, data = 0; |
201 | value = MIPI_CAL_CONFIG_SELECT | | 216 | |
202 | MIPI_CAL_CONFIG_HSPDOS(0) | | 217 | if (device->pads & BIT(i)) { |
203 | MIPI_CAL_CONFIG_HSPUOS(4) | | 218 | data = MIPI_CAL_CONFIG_SELECT | |
204 | MIPI_CAL_CONFIG_TERMOS(5); | 219 | MIPI_CAL_CONFIG_HSPDOS(0) | |
205 | else | 220 | MIPI_CAL_CONFIG_HSPUOS(4) | |
206 | value = 0; | 221 | MIPI_CAL_CONFIG_TERMOS(5); |
222 | clk = MIPI_CAL_CONFIG_SELECT | | ||
223 | MIPI_CAL_CONFIG_HSCLKPDOSD(0) | | ||
224 | MIPI_CAL_CONFIG_HSCLKPUOSD(4); | ||
225 | } | ||
207 | 226 | ||
208 | tegra_mipi_writel(device->mipi, value, modules[i].reg); | 227 | tegra_mipi_writel(device->mipi, data, soc->pads[i].data); |
228 | |||
229 | if (soc->has_clk_lane) | ||
230 | tegra_mipi_writel(device->mipi, clk, soc->pads[i].clk); | ||
209 | } | 231 | } |
210 | 232 | ||
211 | tegra_mipi_writel(device->mipi, MIPI_CAL_CTRL_START, MIPI_CAL_CTRL); | 233 | value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL); |
234 | value |= MIPI_CAL_CTRL_START; | ||
235 | tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL); | ||
212 | 236 | ||
213 | err = tegra_mipi_wait(device->mipi); | 237 | err = tegra_mipi_wait(device->mipi); |
214 | 238 | ||
@@ -219,16 +243,63 @@ int tegra_mipi_calibrate(struct tegra_mipi_device *device) | |||
219 | } | 243 | } |
220 | EXPORT_SYMBOL(tegra_mipi_calibrate); | 244 | EXPORT_SYMBOL(tegra_mipi_calibrate); |
221 | 245 | ||
246 | static const struct tegra_mipi_pad tegra114_mipi_pads[] = { | ||
247 | { .data = MIPI_CAL_CONFIG_CSIA }, | ||
248 | { .data = MIPI_CAL_CONFIG_CSIB }, | ||
249 | { .data = MIPI_CAL_CONFIG_CSIC }, | ||
250 | { .data = MIPI_CAL_CONFIG_CSID }, | ||
251 | { .data = MIPI_CAL_CONFIG_CSIE }, | ||
252 | { .data = MIPI_CAL_CONFIG_DSIA }, | ||
253 | { .data = MIPI_CAL_CONFIG_DSIB }, | ||
254 | { .data = MIPI_CAL_CONFIG_DSIC }, | ||
255 | { .data = MIPI_CAL_CONFIG_DSID }, | ||
256 | }; | ||
257 | |||
258 | static const struct tegra_mipi_soc tegra114_mipi_soc = { | ||
259 | .has_clk_lane = false, | ||
260 | .pads = tegra114_mipi_pads, | ||
261 | .num_pads = ARRAY_SIZE(tegra114_mipi_pads), | ||
262 | }; | ||
263 | |||
264 | static const struct tegra_mipi_pad tegra124_mipi_pads[] = { | ||
265 | { .data = MIPI_CAL_CONFIG_CSIA, .clk = MIPI_CAL_CONFIG_CSIAB_CLK }, | ||
266 | { .data = MIPI_CAL_CONFIG_CSIB, .clk = MIPI_CAL_CONFIG_CSIAB_CLK }, | ||
267 | { .data = MIPI_CAL_CONFIG_CSIC, .clk = MIPI_CAL_CONFIG_CSICD_CLK }, | ||
268 | { .data = MIPI_CAL_CONFIG_CSID, .clk = MIPI_CAL_CONFIG_CSICD_CLK }, | ||
269 | { .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK }, | ||
270 | { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIAB_CLK }, | ||
271 | { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIAB_CLK }, | ||
272 | }; | ||
273 | |||
274 | static const struct tegra_mipi_soc tegra124_mipi_soc = { | ||
275 | .has_clk_lane = true, | ||
276 | .pads = tegra124_mipi_pads, | ||
277 | .num_pads = ARRAY_SIZE(tegra124_mipi_pads), | ||
278 | }; | ||
279 | |||
280 | static struct of_device_id tegra_mipi_of_match[] = { | ||
281 | { .compatible = "nvidia,tegra114-mipi", .data = &tegra114_mipi_soc }, | ||
282 | { .compatible = "nvidia,tegra124-mipi", .data = &tegra124_mipi_soc }, | ||
283 | { }, | ||
284 | }; | ||
285 | |||
222 | static int tegra_mipi_probe(struct platform_device *pdev) | 286 | static int tegra_mipi_probe(struct platform_device *pdev) |
223 | { | 287 | { |
288 | const struct of_device_id *match; | ||
224 | struct tegra_mipi *mipi; | 289 | struct tegra_mipi *mipi; |
225 | struct resource *res; | 290 | struct resource *res; |
226 | int err; | 291 | int err; |
227 | 292 | ||
293 | match = of_match_node(tegra_mipi_of_match, pdev->dev.of_node); | ||
294 | if (!match) | ||
295 | return -ENODEV; | ||
296 | |||
228 | mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL); | 297 | mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL); |
229 | if (!mipi) | 298 | if (!mipi) |
230 | return -ENOMEM; | 299 | return -ENOMEM; |
231 | 300 | ||
301 | mipi->soc = match->data; | ||
302 | |||
232 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 303 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
233 | mipi->regs = devm_ioremap_resource(&pdev->dev, res); | 304 | mipi->regs = devm_ioremap_resource(&pdev->dev, res); |
234 | if (IS_ERR(mipi->regs)) | 305 | if (IS_ERR(mipi->regs)) |
@@ -260,11 +331,6 @@ static int tegra_mipi_remove(struct platform_device *pdev) | |||
260 | return 0; | 331 | return 0; |
261 | } | 332 | } |
262 | 333 | ||
263 | static struct of_device_id tegra_mipi_of_match[] = { | ||
264 | { .compatible = "nvidia,tegra114-mipi", }, | ||
265 | { }, | ||
266 | }; | ||
267 | |||
268 | struct platform_driver tegra_mipi_driver = { | 334 | struct platform_driver tegra_mipi_driver = { |
269 | .driver = { | 335 | .driver = { |
270 | .name = "tegra-mipi", | 336 | .name = "tegra-mipi", |
diff --git a/include/trace/events/host1x.h b/include/trace/events/host1x.h index 94db6a2c3540..63116362543c 100644 --- a/include/trace/events/host1x.h +++ b/include/trace/events/host1x.h | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/ktime.h> | 29 | #include <linux/ktime.h> |
30 | #include <linux/tracepoint.h> | 30 | #include <linux/tracepoint.h> |
31 | 31 | ||
32 | struct host1x_bo; | ||
33 | |||
32 | DECLARE_EVENT_CLASS(host1x, | 34 | DECLARE_EVENT_CLASS(host1x, |
33 | TP_PROTO(const char *name), | 35 | TP_PROTO(const char *name), |
34 | TP_ARGS(name), | 36 | TP_ARGS(name), |
@@ -79,14 +81,14 @@ TRACE_EVENT(host1x_cdma_push, | |||
79 | ); | 81 | ); |
80 | 82 | ||
81 | TRACE_EVENT(host1x_cdma_push_gather, | 83 | TRACE_EVENT(host1x_cdma_push_gather, |
82 | TP_PROTO(const char *name, u32 mem_id, | 84 | TP_PROTO(const char *name, struct host1x_bo *bo, |
83 | u32 words, u32 offset, void *cmdbuf), | 85 | u32 words, u32 offset, void *cmdbuf), |
84 | 86 | ||
85 | TP_ARGS(name, mem_id, words, offset, cmdbuf), | 87 | TP_ARGS(name, bo, words, offset, cmdbuf), |
86 | 88 | ||
87 | TP_STRUCT__entry( | 89 | TP_STRUCT__entry( |
88 | __field(const char *, name) | 90 | __field(const char *, name) |
89 | __field(u32, mem_id) | 91 | __field(struct host1x_bo *, bo) |
90 | __field(u32, words) | 92 | __field(u32, words) |
91 | __field(u32, offset) | 93 | __field(u32, offset) |
92 | __field(bool, cmdbuf) | 94 | __field(bool, cmdbuf) |
@@ -100,13 +102,13 @@ TRACE_EVENT(host1x_cdma_push_gather, | |||
100 | } | 102 | } |
101 | __entry->cmdbuf = cmdbuf; | 103 | __entry->cmdbuf = cmdbuf; |
102 | __entry->name = name; | 104 | __entry->name = name; |
103 | __entry->mem_id = mem_id; | 105 | __entry->bo = bo; |
104 | __entry->words = words; | 106 | __entry->words = words; |
105 | __entry->offset = offset; | 107 | __entry->offset = offset; |
106 | ), | 108 | ), |
107 | 109 | ||
108 | TP_printk("name=%s, mem_id=%08x, words=%u, offset=%d, contents=[%s]", | 110 | TP_printk("name=%s, bo=%p, words=%u, offset=%d, contents=[%s]", |
109 | __entry->name, __entry->mem_id, | 111 | __entry->name, __entry->bo, |
110 | __entry->words, __entry->offset, | 112 | __entry->words, __entry->offset, |
111 | __print_hex(__get_dynamic_array(cmdbuf), | 113 | __print_hex(__get_dynamic_array(cmdbuf), |
112 | __entry->cmdbuf ? __entry->words * 4 : 0)) | 114 | __entry->cmdbuf ? __entry->words * 4 : 0)) |
@@ -221,12 +223,13 @@ TRACE_EVENT(host1x_syncpt_load_min, | |||
221 | ); | 223 | ); |
222 | 224 | ||
223 | TRACE_EVENT(host1x_syncpt_wait_check, | 225 | TRACE_EVENT(host1x_syncpt_wait_check, |
224 | TP_PROTO(void *mem_id, u32 offset, u32 syncpt_id, u32 thresh, u32 min), | 226 | TP_PROTO(struct host1x_bo *bo, u32 offset, u32 syncpt_id, u32 thresh, |
227 | u32 min), | ||
225 | 228 | ||
226 | TP_ARGS(mem_id, offset, syncpt_id, thresh, min), | 229 | TP_ARGS(bo, offset, syncpt_id, thresh, min), |
227 | 230 | ||
228 | TP_STRUCT__entry( | 231 | TP_STRUCT__entry( |
229 | __field(void *, mem_id) | 232 | __field(struct host1x_bo *, bo) |
230 | __field(u32, offset) | 233 | __field(u32, offset) |
231 | __field(u32, syncpt_id) | 234 | __field(u32, syncpt_id) |
232 | __field(u32, thresh) | 235 | __field(u32, thresh) |
@@ -234,15 +237,15 @@ TRACE_EVENT(host1x_syncpt_wait_check, | |||
234 | ), | 237 | ), |
235 | 238 | ||
236 | TP_fast_assign( | 239 | TP_fast_assign( |
237 | __entry->mem_id = mem_id; | 240 | __entry->bo = bo; |
238 | __entry->offset = offset; | 241 | __entry->offset = offset; |
239 | __entry->syncpt_id = syncpt_id; | 242 | __entry->syncpt_id = syncpt_id; |
240 | __entry->thresh = thresh; | 243 | __entry->thresh = thresh; |
241 | __entry->min = min; | 244 | __entry->min = min; |
242 | ), | 245 | ), |
243 | 246 | ||
244 | TP_printk("mem_id=%p, offset=%05x, id=%d, thresh=%d, current=%d", | 247 | TP_printk("bo=%p, offset=%05x, id=%d, thresh=%d, current=%d", |
245 | __entry->mem_id, __entry->offset, | 248 | __entry->bo, __entry->offset, |
246 | __entry->syncpt_id, __entry->thresh, | 249 | __entry->syncpt_id, __entry->thresh, |
247 | __entry->min) | 250 | __entry->min) |
248 | ); | 251 | ); |