aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-10-24 02:50:45 -0400
committerDave Airlie <airlied@redhat.com>2017-10-24 02:50:45 -0400
commit3b677e43c1191de4717357ffeb85a30b967045e4 (patch)
tree076e053e367e3b6525614808f3d8c81e77b434ca
parent3064abfa932bd09faf8da01741d171d476cf7193 (diff)
parentfb83be8873909ba7c089d1c5cb72873cc2cce7d1 (diff)
Merge tag 'drm/tegra/for-4.15-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next
drm/tegra: Changes for v4.15-rc1 This contains a bit of cleanup and some minor fixes for the host1x and Tegra DRM drivers. There's also some more preparatory work for Tegra186 support which I'm not quite ready to send upstream because the GPIO driver needed for HDMI support has been stuck for months, and we can't do much without it. Hopefully that driver will land in v4.15, which would mean we could go ahead with Tegra186 display support in v4.16. * tag 'drm/tegra/for-4.15-rc1' of git://anongit.freedesktop.org/tegra/linux: (21 commits) drm/tegra: hdmi: Add cec-notifier support drm/tegra: dc: Perform a complete reset sequence drm/tegra: dc: Make sure to set the module clock rate drm/tegra: dc: Simplify atomic plane helper functions drm/tegra: dc: Move some declarations to dc.h drm/tegra: vic: Use of_device_get_match_data() drm/tegra: sor: Use of_device_get_match_data() drm/tegra: hdmi: Use of_device_get_match_data() drm/tegra: dc: Use of_device_get_match_data() drm/tegra: Use u64_to_user_ptr helper gpu: host1x: Fix incorrect comment for channel_request gpu: host1x: Disassemble more instructions gpu: host1x: Improve debug disassembly formatting gpu: host1x: Enable gather filter gpu: host1x: Enable Tegra186 syncpoint protection gpu: host1x: Call of_dma_configure() after setting bus drm/tegra: Add Tegra186 support for VIC gpu: host1x: Add Tegra186 support dt-bindings: host1x: Add Tegra186 information gpu: host1x: syncpt: Request syncpoints per client ...
-rw-r--r--Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt4
-rw-r--r--drivers/gpu/drm/tegra/Kconfig1
-rw-r--r--drivers/gpu/drm/tegra/dc.c84
-rw-r--r--drivers/gpu/drm/tegra/dc.h120
-rw-r--r--drivers/gpu/drm/tegra/drm.c30
-rw-r--r--drivers/gpu/drm/tegra/drm.h106
-rw-r--r--drivers/gpu/drm/tegra/gr2d.c2
-rw-r--r--drivers/gpu/drm/tegra/gr3d.c2
-rw-r--r--drivers/gpu/drm/tegra/hdmi.c17
-rw-r--r--drivers/gpu/drm/tegra/output.c6
-rw-r--r--drivers/gpu/drm/tegra/sor.c5
-rw-r--r--drivers/gpu/drm/tegra/vic.c22
-rw-r--r--drivers/gpu/host1x/Makefile3
-rw-r--r--drivers/gpu/host1x/bus.c3
-rw-r--r--drivers/gpu/host1x/channel.c3
-rw-r--r--drivers/gpu/host1x/debug.c14
-rw-r--r--drivers/gpu/host1x/debug.h14
-rw-r--r--drivers/gpu/host1x/dev.c69
-rw-r--r--drivers/gpu/host1x/dev.h19
-rw-r--r--drivers/gpu/host1x/hw/cdma_hw.c49
-rw-r--r--drivers/gpu/host1x/hw/channel_hw.c24
-rw-r--r--drivers/gpu/host1x/hw/debug_hw.c240
-rw-r--r--drivers/gpu/host1x/hw/debug_hw_1x01.c154
-rw-r--r--drivers/gpu/host1x/hw/debug_hw_1x06.c135
-rw-r--r--drivers/gpu/host1x/hw/host1x01.c2
-rw-r--r--drivers/gpu/host1x/hw/host1x02.c2
-rw-r--r--drivers/gpu/host1x/hw/host1x04.c2
-rw-r--r--drivers/gpu/host1x/hw/host1x05.c2
-rw-r--r--drivers/gpu/host1x/hw/host1x06.c44
-rw-r--r--drivers/gpu/host1x/hw/host1x06.h26
-rw-r--r--drivers/gpu/host1x/hw/host1x06_hardware.h142
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x04_channel.h12
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x05_channel.h12
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x06_hypervisor.h32
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x06_uclass.h181
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x06_vm.h47
-rw-r--r--drivers/gpu/host1x/hw/intr_hw.c29
-rw-r--r--drivers/gpu/host1x/hw/syncpt_hw.c46
-rw-r--r--drivers/gpu/host1x/syncpt.c24
-rw-r--r--drivers/gpu/host1x/syncpt.h2
-rw-r--r--include/linux/host1x.h2
41 files changed, 1334 insertions, 399 deletions
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
index 74e1e8add5a1..844e0103fb0d 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
@@ -3,6 +3,10 @@ NVIDIA Tegra host1x
3Required properties: 3Required properties:
4- compatible: "nvidia,tegra<chip>-host1x" 4- compatible: "nvidia,tegra<chip>-host1x"
5- reg: Physical base address and length of the controller's registers. 5- reg: Physical base address and length of the controller's registers.
6 For pre-Tegra186, one entry describing the whole register area.
7 For Tegra186, one entry for each entry in reg-names:
8 "vm" - VM region assigned to Linux
9 "hypervisor" - Hypervisor region (only if Linux acts as hypervisor)
6- interrupts: The interrupt outputs from the controller. 10- interrupts: The interrupt outputs from the controller.
7- #address-cells: The number of cells used to represent physical base addresses 11- #address-cells: The number of cells used to represent physical base addresses
8 in the host1x address space. Should be 1. 12 in the host1x address space. Should be 1.
diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig
index dc58ab140151..cf54847a8bd1 100644
--- a/drivers/gpu/drm/tegra/Kconfig
+++ b/drivers/gpu/drm/tegra/Kconfig
@@ -9,6 +9,7 @@ config DRM_TEGRA
9 select DRM_PANEL 9 select DRM_PANEL
10 select TEGRA_HOST1X 10 select TEGRA_HOST1X
11 select IOMMU_IOVA if IOMMU_SUPPORT 11 select IOMMU_IOVA if IOMMU_SUPPORT
12 select CEC_CORE if CEC_NOTIFIER
12 help 13 help
13 Choose this option if you have an NVIDIA Tegra SoC. 14 Choose this option if you have an NVIDIA Tegra SoC.
14 15
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 4df39112e38e..24a5ef4f5bb8 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -10,6 +10,7 @@
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/iommu.h>
13#include <linux/of_device.h>
13#include <linux/pm_runtime.h> 14#include <linux/pm_runtime.h>
14#include <linux/reset.h> 15#include <linux/reset.h>
15 16
@@ -23,16 +24,6 @@
23#include <drm/drm_atomic_helper.h> 24#include <drm/drm_atomic_helper.h>
24#include <drm/drm_plane_helper.h> 25#include <drm/drm_plane_helper.h>
25 26
26struct tegra_dc_soc_info {
27 bool supports_border_color;
28 bool supports_interlacing;
29 bool supports_cursor;
30 bool supports_block_linear;
31 unsigned int pitch_align;
32 bool has_powergate;
33 bool broken_reset;
34};
35
36struct tegra_plane { 27struct tegra_plane {
37 struct drm_plane base; 28 struct drm_plane base;
38 unsigned int index; 29 unsigned int index;
@@ -559,14 +550,21 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
559 return 0; 550 return 0;
560} 551}
561 552
562static void tegra_dc_disable_window(struct tegra_dc *dc, int index) 553static void tegra_plane_atomic_disable(struct drm_plane *plane,
554 struct drm_plane_state *old_state)
563{ 555{
556 struct tegra_dc *dc = to_tegra_dc(old_state->crtc);
557 struct tegra_plane *p = to_tegra_plane(plane);
564 unsigned long flags; 558 unsigned long flags;
565 u32 value; 559 u32 value;
566 560
561 /* rien ne va plus */
562 if (!old_state || !old_state->crtc)
563 return;
564
567 spin_lock_irqsave(&dc->lock, flags); 565 spin_lock_irqsave(&dc->lock, flags);
568 566
569 value = WINDOW_A_SELECT << index; 567 value = WINDOW_A_SELECT << p->index;
570 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); 568 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
571 569
572 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); 570 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
@@ -591,7 +589,7 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
591 return; 589 return;
592 590
593 if (!plane->state->visible) 591 if (!plane->state->visible)
594 return tegra_dc_disable_window(dc, p->index); 592 return tegra_plane_atomic_disable(plane, old_state);
595 593
596 memset(&window, 0, sizeof(window)); 594 memset(&window, 0, sizeof(window));
597 window.src.x = plane->state->src.x1 >> 16; 595 window.src.x = plane->state->src.x1 >> 16;
@@ -627,25 +625,10 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
627 tegra_dc_setup_window(dc, p->index, &window); 625 tegra_dc_setup_window(dc, p->index, &window);
628} 626}
629 627
630static void tegra_plane_atomic_disable(struct drm_plane *plane, 628static const struct drm_plane_helper_funcs tegra_plane_helper_funcs = {
631 struct drm_plane_state *old_state)
632{
633 struct tegra_plane *p = to_tegra_plane(plane);
634 struct tegra_dc *dc;
635
636 /* rien ne va plus */
637 if (!old_state || !old_state->crtc)
638 return;
639
640 dc = to_tegra_dc(old_state->crtc);
641
642 tegra_dc_disable_window(dc, p->index);
643}
644
645static const struct drm_plane_helper_funcs tegra_primary_plane_helper_funcs = {
646 .atomic_check = tegra_plane_atomic_check, 629 .atomic_check = tegra_plane_atomic_check,
647 .atomic_update = tegra_plane_atomic_update,
648 .atomic_disable = tegra_plane_atomic_disable, 630 .atomic_disable = tegra_plane_atomic_disable,
631 .atomic_update = tegra_plane_atomic_update,
649}; 632};
650 633
651static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm, 634static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
@@ -685,7 +668,7 @@ static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
685 return ERR_PTR(err); 668 return ERR_PTR(err);
686 } 669 }
687 670
688 drm_plane_helper_add(&plane->base, &tegra_primary_plane_helper_funcs); 671 drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);
689 672
690 return &plane->base; 673 return &plane->base;
691} 674}
@@ -880,12 +863,6 @@ static const uint32_t tegra_overlay_plane_formats[] = {
880 DRM_FORMAT_YUV422, 863 DRM_FORMAT_YUV422,
881}; 864};
882 865
883static const struct drm_plane_helper_funcs tegra_overlay_plane_helper_funcs = {
884 .atomic_check = tegra_plane_atomic_check,
885 .atomic_update = tegra_plane_atomic_update,
886 .atomic_disable = tegra_plane_atomic_disable,
887};
888
889static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, 866static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
890 struct tegra_dc *dc, 867 struct tegra_dc *dc,
891 unsigned int index) 868 unsigned int index)
@@ -913,7 +890,7 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
913 return ERR_PTR(err); 890 return ERR_PTR(err);
914 } 891 }
915 892
916 drm_plane_helper_add(&plane->base, &tegra_overlay_plane_helper_funcs); 893 drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);
917 894
918 return &plane->base; 895 return &plane->base;
919} 896}
@@ -1161,6 +1138,11 @@ static void tegra_dc_commit_state(struct tegra_dc *dc,
1161 1138
1162 value = SHIFT_CLK_DIVIDER(state->div) | PIXEL_CLK_DIVIDER_PCD1; 1139 value = SHIFT_CLK_DIVIDER(state->div) | PIXEL_CLK_DIVIDER_PCD1;
1163 tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); 1140 tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
1141
1142 err = clk_set_rate(dc->clk, state->pclk);
1143 if (err < 0)
1144 dev_err(dc->dev, "failed to set clock %pC to %lu Hz: %d\n",
1145 dc->clk, state->pclk, err);
1164} 1146}
1165 1147
1166static void tegra_dc_stop(struct tegra_dc *dc) 1148static void tegra_dc_stop(struct tegra_dc *dc)
@@ -1756,7 +1738,7 @@ static int tegra_dc_init(struct host1x_client *client)
1756 struct drm_plane *cursor = NULL; 1738 struct drm_plane *cursor = NULL;
1757 int err; 1739 int err;
1758 1740
1759 dc->syncpt = host1x_syncpt_request(dc->dev, flags); 1741 dc->syncpt = host1x_syncpt_request(client, flags);
1760 if (!dc->syncpt) 1742 if (!dc->syncpt)
1761 dev_warn(dc->dev, "failed to allocate syncpoint\n"); 1743 dev_warn(dc->dev, "failed to allocate syncpoint\n");
1762 1744
@@ -1985,7 +1967,6 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
1985 1967
1986static int tegra_dc_probe(struct platform_device *pdev) 1968static int tegra_dc_probe(struct platform_device *pdev)
1987{ 1969{
1988 const struct of_device_id *id;
1989 struct resource *regs; 1970 struct resource *regs;
1990 struct tegra_dc *dc; 1971 struct tegra_dc *dc;
1991 int err; 1972 int err;
@@ -1994,14 +1975,11 @@ static int tegra_dc_probe(struct platform_device *pdev)
1994 if (!dc) 1975 if (!dc)
1995 return -ENOMEM; 1976 return -ENOMEM;
1996 1977
1997 id = of_match_node(tegra_dc_of_match, pdev->dev.of_node); 1978 dc->soc = of_device_get_match_data(&pdev->dev);
1998 if (!id)
1999 return -ENODEV;
2000 1979
2001 spin_lock_init(&dc->lock); 1980 spin_lock_init(&dc->lock);
2002 INIT_LIST_HEAD(&dc->list); 1981 INIT_LIST_HEAD(&dc->list);
2003 dc->dev = &pdev->dev; 1982 dc->dev = &pdev->dev;
2004 dc->soc = id->data;
2005 1983
2006 err = tegra_dc_parse_dt(dc); 1984 err = tegra_dc_parse_dt(dc);
2007 if (err < 0) 1985 if (err < 0)
@@ -2019,8 +1997,22 @@ static int tegra_dc_probe(struct platform_device *pdev)
2019 return PTR_ERR(dc->rst); 1997 return PTR_ERR(dc->rst);
2020 } 1998 }
2021 1999
2022 if (!dc->soc->broken_reset) 2000 /* assert reset and disable clock */
2023 reset_control_assert(dc->rst); 2001 if (!dc->soc->broken_reset) {
2002 err = clk_prepare_enable(dc->clk);
2003 if (err < 0)
2004 return err;
2005
2006 usleep_range(2000, 4000);
2007
2008 err = reset_control_assert(dc->rst);
2009 if (err < 0)
2010 return err;
2011
2012 usleep_range(2000, 4000);
2013
2014 clk_disable_unprepare(dc->clk);
2015 }
2024 2016
2025 if (dc->soc->has_powergate) { 2017 if (dc->soc->has_powergate) {
2026 if (dc->pipe == 0) 2018 if (dc->pipe == 0)
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 4a268635749b..cb100b6e3282 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -10,6 +10,126 @@
10#ifndef TEGRA_DC_H 10#ifndef TEGRA_DC_H
11#define TEGRA_DC_H 1 11#define TEGRA_DC_H 1
12 12
13#include <linux/host1x.h>
14
15#include <drm/drm_crtc.h>
16
17#include "drm.h"
18
19struct tegra_output;
20
21struct tegra_dc_stats {
22 unsigned long frames;
23 unsigned long vblank;
24 unsigned long underflow;
25 unsigned long overflow;
26};
27
28struct tegra_dc_soc_info {
29 bool supports_border_color;
30 bool supports_interlacing;
31 bool supports_cursor;
32 bool supports_block_linear;
33 unsigned int pitch_align;
34 bool has_powergate;
35 bool broken_reset;
36};
37
38struct tegra_dc {
39 struct host1x_client client;
40 struct host1x_syncpt *syncpt;
41 struct device *dev;
42 spinlock_t lock;
43
44 struct drm_crtc base;
45 unsigned int powergate;
46 int pipe;
47
48 struct clk *clk;
49 struct reset_control *rst;
50 void __iomem *regs;
51 int irq;
52
53 struct tegra_output *rgb;
54
55 struct tegra_dc_stats stats;
56 struct list_head list;
57
58 struct drm_info_list *debugfs_files;
59 struct drm_minor *minor;
60 struct dentry *debugfs;
61
62 /* page-flip handling */
63 struct drm_pending_vblank_event *event;
64
65 const struct tegra_dc_soc_info *soc;
66
67 struct iommu_domain *domain;
68};
69
70static inline struct tegra_dc *
71host1x_client_to_dc(struct host1x_client *client)
72{
73 return container_of(client, struct tegra_dc, client);
74}
75
76static inline struct tegra_dc *to_tegra_dc(struct drm_crtc *crtc)
77{
78 return crtc ? container_of(crtc, struct tegra_dc, base) : NULL;
79}
80
81static inline void tegra_dc_writel(struct tegra_dc *dc, u32 value,
82 unsigned int offset)
83{
84 trace_dc_writel(dc->dev, offset, value);
85 writel(value, dc->regs + (offset << 2));
86}
87
88static inline u32 tegra_dc_readl(struct tegra_dc *dc, unsigned int offset)
89{
90 u32 value = readl(dc->regs + (offset << 2));
91
92 trace_dc_readl(dc->dev, offset, value);
93
94 return value;
95}
96
97struct tegra_dc_window {
98 struct {
99 unsigned int x;
100 unsigned int y;
101 unsigned int w;
102 unsigned int h;
103 } src;
104 struct {
105 unsigned int x;
106 unsigned int y;
107 unsigned int w;
108 unsigned int h;
109 } dst;
110 unsigned int bits_per_pixel;
111 unsigned int stride[2];
112 unsigned long base[3];
113 bool bottom_up;
114
115 struct tegra_bo_tiling tiling;
116 u32 format;
117 u32 swap;
118};
119
120/* from dc.c */
121void tegra_dc_commit(struct tegra_dc *dc);
122int tegra_dc_state_setup_clock(struct tegra_dc *dc,
123 struct drm_crtc_state *crtc_state,
124 struct clk *clk, unsigned long pclk,
125 unsigned int div);
126
127/* from rgb.c */
128int tegra_dc_rgb_probe(struct tegra_dc *dc);
129int tegra_dc_rgb_remove(struct tegra_dc *dc);
130int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc);
131int tegra_dc_rgb_exit(struct tegra_dc *dc);
132
13#define DC_CMD_GENERAL_INCR_SYNCPT 0x000 133#define DC_CMD_GENERAL_INCR_SYNCPT 0x000
14#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001 134#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001
15#define SYNCPT_CNTRL_NO_STALL (1 << 8) 135#define SYNCPT_CNTRL_NO_STALL (1 << 8)
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 597d563d636a..943bdf88c4a2 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -386,12 +386,10 @@ int tegra_drm_submit(struct tegra_drm_context *context,
386 unsigned int num_cmdbufs = args->num_cmdbufs; 386 unsigned int num_cmdbufs = args->num_cmdbufs;
387 unsigned int num_relocs = args->num_relocs; 387 unsigned int num_relocs = args->num_relocs;
388 unsigned int num_waitchks = args->num_waitchks; 388 unsigned int num_waitchks = args->num_waitchks;
389 struct drm_tegra_cmdbuf __user *cmdbufs = 389 struct drm_tegra_cmdbuf __user *user_cmdbufs;
390 (void __user *)(uintptr_t)args->cmdbufs; 390 struct drm_tegra_reloc __user *user_relocs;
391 struct drm_tegra_reloc __user *relocs = 391 struct drm_tegra_waitchk __user *user_waitchks;
392 (void __user *)(uintptr_t)args->relocs; 392 struct drm_tegra_syncpt __user *user_syncpt;
393 struct drm_tegra_waitchk __user *waitchks =
394 (void __user *)(uintptr_t)args->waitchks;
395 struct drm_tegra_syncpt syncpt; 393 struct drm_tegra_syncpt syncpt;
396 struct host1x *host1x = dev_get_drvdata(drm->dev->parent); 394 struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
397 struct drm_gem_object **refs; 395 struct drm_gem_object **refs;
@@ -400,6 +398,11 @@ int tegra_drm_submit(struct tegra_drm_context *context,
400 unsigned int num_refs; 398 unsigned int num_refs;
401 int err; 399 int err;
402 400
401 user_cmdbufs = u64_to_user_ptr(args->cmdbufs);
402 user_relocs = u64_to_user_ptr(args->relocs);
403 user_waitchks = u64_to_user_ptr(args->waitchks);
404 user_syncpt = u64_to_user_ptr(args->syncpts);
405
403 /* We don't yet support other than one syncpt_incr struct per submit */ 406 /* We don't yet support other than one syncpt_incr struct per submit */
404 if (args->num_syncpts != 1) 407 if (args->num_syncpts != 1)
405 return -EINVAL; 408 return -EINVAL;
@@ -440,7 +443,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
440 struct tegra_bo *obj; 443 struct tegra_bo *obj;
441 u64 offset; 444 u64 offset;
442 445
443 if (copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf))) { 446 if (copy_from_user(&cmdbuf, user_cmdbufs, sizeof(cmdbuf))) {
444 err = -EFAULT; 447 err = -EFAULT;
445 goto fail; 448 goto fail;
446 } 449 }
@@ -476,7 +479,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
476 479
477 host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset); 480 host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
478 num_cmdbufs--; 481 num_cmdbufs--;
479 cmdbufs++; 482 user_cmdbufs++;
480 } 483 }
481 484
482 /* copy and resolve relocations from submit */ 485 /* copy and resolve relocations from submit */
@@ -485,7 +488,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
485 struct tegra_bo *obj; 488 struct tegra_bo *obj;
486 489
487 err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs], 490 err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs],
488 &relocs[num_relocs], drm, 491 &user_relocs[num_relocs], drm,
489 file); 492 file);
490 if (err < 0) 493 if (err < 0)
491 goto fail; 494 goto fail;
@@ -519,9 +522,8 @@ int tegra_drm_submit(struct tegra_drm_context *context,
519 struct host1x_waitchk *wait = &job->waitchk[num_waitchks]; 522 struct host1x_waitchk *wait = &job->waitchk[num_waitchks];
520 struct tegra_bo *obj; 523 struct tegra_bo *obj;
521 524
522 err = host1x_waitchk_copy_from_user(wait, 525 err = host1x_waitchk_copy_from_user(
523 &waitchks[num_waitchks], 526 wait, &user_waitchks[num_waitchks], file);
524 file);
525 if (err < 0) 527 if (err < 0)
526 goto fail; 528 goto fail;
527 529
@@ -539,8 +541,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
539 } 541 }
540 } 542 }
541 543
542 if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts, 544 if (copy_from_user(&syncpt, user_syncpt, sizeof(syncpt))) {
543 sizeof(syncpt))) {
544 err = -EFAULT; 545 err = -EFAULT;
545 goto fail; 546 goto fail;
546 } 547 }
@@ -1317,6 +1318,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
1317 { .compatible = "nvidia,tegra210-sor", }, 1318 { .compatible = "nvidia,tegra210-sor", },
1318 { .compatible = "nvidia,tegra210-sor1", }, 1319 { .compatible = "nvidia,tegra210-sor1", },
1319 { .compatible = "nvidia,tegra210-vic", }, 1320 { .compatible = "nvidia,tegra210-vic", },
1321 { .compatible = "nvidia,tegra186-vic", },
1320 { /* sentinel */ } 1322 { /* sentinel */ }
1321}; 1323};
1322 1324
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 063f5d397526..ddae331ad8b6 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -119,104 +119,7 @@ void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *iova);
119void tegra_drm_free(struct tegra_drm *tegra, size_t size, void *virt, 119void tegra_drm_free(struct tegra_drm *tegra, size_t size, void *virt,
120 dma_addr_t iova); 120 dma_addr_t iova);
121 121
122struct tegra_dc_soc_info; 122struct cec_notifier;
123struct tegra_output;
124
125struct tegra_dc_stats {
126 unsigned long frames;
127 unsigned long vblank;
128 unsigned long underflow;
129 unsigned long overflow;
130};
131
132struct tegra_dc {
133 struct host1x_client client;
134 struct host1x_syncpt *syncpt;
135 struct device *dev;
136 spinlock_t lock;
137
138 struct drm_crtc base;
139 unsigned int powergate;
140 int pipe;
141
142 struct clk *clk;
143 struct reset_control *rst;
144 void __iomem *regs;
145 int irq;
146
147 struct tegra_output *rgb;
148
149 struct tegra_dc_stats stats;
150 struct list_head list;
151
152 struct drm_info_list *debugfs_files;
153 struct drm_minor *minor;
154 struct dentry *debugfs;
155
156 /* page-flip handling */
157 struct drm_pending_vblank_event *event;
158
159 const struct tegra_dc_soc_info *soc;
160
161 struct iommu_domain *domain;
162};
163
164static inline struct tegra_dc *
165host1x_client_to_dc(struct host1x_client *client)
166{
167 return container_of(client, struct tegra_dc, client);
168}
169
170static inline struct tegra_dc *to_tegra_dc(struct drm_crtc *crtc)
171{
172 return crtc ? container_of(crtc, struct tegra_dc, base) : NULL;
173}
174
175static inline void tegra_dc_writel(struct tegra_dc *dc, u32 value,
176 unsigned int offset)
177{
178 trace_dc_writel(dc->dev, offset, value);
179 writel(value, dc->regs + (offset << 2));
180}
181
182static inline u32 tegra_dc_readl(struct tegra_dc *dc, unsigned int offset)
183{
184 u32 value = readl(dc->regs + (offset << 2));
185
186 trace_dc_readl(dc->dev, offset, value);
187
188 return value;
189}
190
191struct tegra_dc_window {
192 struct {
193 unsigned int x;
194 unsigned int y;
195 unsigned int w;
196 unsigned int h;
197 } src;
198 struct {
199 unsigned int x;
200 unsigned int y;
201 unsigned int w;
202 unsigned int h;
203 } dst;
204 unsigned int bits_per_pixel;
205 unsigned int stride[2];
206 unsigned long base[3];
207 bool bottom_up;
208
209 struct tegra_bo_tiling tiling;
210 u32 format;
211 u32 swap;
212};
213
214/* from dc.c */
215void tegra_dc_commit(struct tegra_dc *dc);
216int tegra_dc_state_setup_clock(struct tegra_dc *dc,
217 struct drm_crtc_state *crtc_state,
218 struct clk *clk, unsigned long pclk,
219 unsigned int div);
220 123
221struct tegra_output { 124struct tegra_output {
222 struct device_node *of_node; 125 struct device_node *of_node;
@@ -225,6 +128,7 @@ struct tegra_output {
225 struct drm_panel *panel; 128 struct drm_panel *panel;
226 struct i2c_adapter *ddc; 129 struct i2c_adapter *ddc;
227 const struct edid *edid; 130 const struct edid *edid;
131 struct cec_notifier *notifier;
228 unsigned int hpd_irq; 132 unsigned int hpd_irq;
229 int hpd_gpio; 133 int hpd_gpio;
230 enum of_gpio_flags hpd_gpio_flags; 134 enum of_gpio_flags hpd_gpio_flags;
@@ -243,12 +147,6 @@ static inline struct tegra_output *connector_to_output(struct drm_connector *c)
243 return container_of(c, struct tegra_output, connector); 147 return container_of(c, struct tegra_output, connector);
244} 148}
245 149
246/* from rgb.c */
247int tegra_dc_rgb_probe(struct tegra_dc *dc);
248int tegra_dc_rgb_remove(struct tegra_dc *dc);
249int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc);
250int tegra_dc_rgb_exit(struct tegra_dc *dc);
251
252/* from output.c */ 150/* from output.c */
253int tegra_output_probe(struct tegra_output *output); 151int tegra_output_probe(struct tegra_output *output);
254void tegra_output_remove(struct tegra_output *output); 152void tegra_output_remove(struct tegra_output *output);
diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c
index 6ea070da7718..9a8ea93016a9 100644
--- a/drivers/gpu/drm/tegra/gr2d.c
+++ b/drivers/gpu/drm/tegra/gr2d.c
@@ -36,7 +36,7 @@ static int gr2d_init(struct host1x_client *client)
36 if (!gr2d->channel) 36 if (!gr2d->channel)
37 return -ENOMEM; 37 return -ENOMEM;
38 38
39 client->syncpts[0] = host1x_syncpt_request(client->dev, flags); 39 client->syncpts[0] = host1x_syncpt_request(client, flags);
40 if (!client->syncpts[0]) { 40 if (!client->syncpts[0]) {
41 host1x_channel_put(gr2d->channel); 41 host1x_channel_put(gr2d->channel);
42 return -ENOMEM; 42 return -ENOMEM;
diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c
index cee2ab645cde..28c4ef63065b 100644
--- a/drivers/gpu/drm/tegra/gr3d.c
+++ b/drivers/gpu/drm/tegra/gr3d.c
@@ -46,7 +46,7 @@ static int gr3d_init(struct host1x_client *client)
46 if (!gr3d->channel) 46 if (!gr3d->channel)
47 return -ENOMEM; 47 return -ENOMEM;
48 48
49 client->syncpts[0] = host1x_syncpt_request(client->dev, flags); 49 client->syncpts[0] = host1x_syncpt_request(client, flags);
50 if (!client->syncpts[0]) { 50 if (!client->syncpts[0]) {
51 host1x_channel_put(gr3d->channel); 51 host1x_channel_put(gr3d->channel);
52 return -ENOMEM; 52 return -ENOMEM;
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index 5b9d83b71943..6434b3d3d1ba 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -11,6 +11,7 @@
11#include <linux/debugfs.h> 11#include <linux/debugfs.h>
12#include <linux/gpio.h> 12#include <linux/gpio.h>
13#include <linux/hdmi.h> 13#include <linux/hdmi.h>
14#include <linux/of_device.h>
14#include <linux/pm_runtime.h> 15#include <linux/pm_runtime.h>
15#include <linux/regulator/consumer.h> 16#include <linux/regulator/consumer.h>
16#include <linux/reset.h> 17#include <linux/reset.h>
@@ -21,6 +22,8 @@
21 22
22#include <sound/hda_verbs.h> 23#include <sound/hda_verbs.h>
23 24
25#include <media/cec-notifier.h>
26
24#include "hdmi.h" 27#include "hdmi.h"
25#include "drm.h" 28#include "drm.h"
26#include "dc.h" 29#include "dc.h"
@@ -1663,20 +1666,15 @@ static irqreturn_t tegra_hdmi_irq(int irq, void *data)
1663 1666
1664static int tegra_hdmi_probe(struct platform_device *pdev) 1667static int tegra_hdmi_probe(struct platform_device *pdev)
1665{ 1668{
1666 const struct of_device_id *match;
1667 struct tegra_hdmi *hdmi; 1669 struct tegra_hdmi *hdmi;
1668 struct resource *regs; 1670 struct resource *regs;
1669 int err; 1671 int err;
1670 1672
1671 match = of_match_node(tegra_hdmi_of_match, pdev->dev.of_node);
1672 if (!match)
1673 return -ENODEV;
1674
1675 hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); 1673 hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
1676 if (!hdmi) 1674 if (!hdmi)
1677 return -ENOMEM; 1675 return -ENOMEM;
1678 1676
1679 hdmi->config = match->data; 1677 hdmi->config = of_device_get_match_data(&pdev->dev);
1680 hdmi->dev = &pdev->dev; 1678 hdmi->dev = &pdev->dev;
1681 1679
1682 hdmi->audio_source = AUTO; 1680 hdmi->audio_source = AUTO;
@@ -1725,6 +1723,10 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
1725 return PTR_ERR(hdmi->vdd); 1723 return PTR_ERR(hdmi->vdd);
1726 } 1724 }
1727 1725
1726 hdmi->output.notifier = cec_notifier_get(&pdev->dev);
1727 if (hdmi->output.notifier == NULL)
1728 return -ENOMEM;
1729
1728 hdmi->output.dev = &pdev->dev; 1730 hdmi->output.dev = &pdev->dev;
1729 1731
1730 err = tegra_output_probe(&hdmi->output); 1732 err = tegra_output_probe(&hdmi->output);
@@ -1783,6 +1785,9 @@ static int tegra_hdmi_remove(struct platform_device *pdev)
1783 1785
1784 tegra_output_remove(&hdmi->output); 1786 tegra_output_remove(&hdmi->output);
1785 1787
1788 if (hdmi->output.notifier)
1789 cec_notifier_put(hdmi->output.notifier);
1790
1786 return 0; 1791 return 0;
1787} 1792}
1788 1793
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index 595d1ec3e02e..1cfbacea8113 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -11,6 +11,8 @@
11#include <drm/drm_panel.h> 11#include <drm/drm_panel.h>
12#include "drm.h" 12#include "drm.h"
13 13
14#include <media/cec-notifier.h>
15
14int tegra_output_connector_get_modes(struct drm_connector *connector) 16int tegra_output_connector_get_modes(struct drm_connector *connector)
15{ 17{
16 struct tegra_output *output = connector_to_output(connector); 18 struct tegra_output *output = connector_to_output(connector);
@@ -32,6 +34,7 @@ int tegra_output_connector_get_modes(struct drm_connector *connector)
32 else if (output->ddc) 34 else if (output->ddc)
33 edid = drm_get_edid(connector, output->ddc); 35 edid = drm_get_edid(connector, output->ddc);
34 36
37 cec_notifier_set_phys_addr_from_edid(output->notifier, edid);
35 drm_mode_connector_update_edid_property(connector, edid); 38 drm_mode_connector_update_edid_property(connector, edid);
36 39
37 if (edid) { 40 if (edid) {
@@ -68,6 +71,9 @@ tegra_output_connector_detect(struct drm_connector *connector, bool force)
68 status = connector_status_connected; 71 status = connector_status_connected;
69 } 72 }
70 73
74 if (status != connector_status_connected)
75 cec_notifier_phys_addr_invalidate(output->notifier);
76
71 return status; 77 return status;
72} 78}
73 79
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 7ab1d1dc7cd7..4bcacd3f4861 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -2536,20 +2536,17 @@ MODULE_DEVICE_TABLE(of, tegra_sor_of_match);
2536 2536
2537static int tegra_sor_probe(struct platform_device *pdev) 2537static int tegra_sor_probe(struct platform_device *pdev)
2538{ 2538{
2539 const struct of_device_id *match;
2540 struct device_node *np; 2539 struct device_node *np;
2541 struct tegra_sor *sor; 2540 struct tegra_sor *sor;
2542 struct resource *regs; 2541 struct resource *regs;
2543 int err; 2542 int err;
2544 2543
2545 match = of_match_device(tegra_sor_of_match, &pdev->dev);
2546
2547 sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL); 2544 sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL);
2548 if (!sor) 2545 if (!sor)
2549 return -ENOMEM; 2546 return -ENOMEM;
2550 2547
2548 sor->soc = of_device_get_match_data(&pdev->dev);
2551 sor->output.dev = sor->dev = &pdev->dev; 2549 sor->output.dev = sor->dev = &pdev->dev;
2552 sor->soc = match->data;
2553 2550
2554 sor->settings = devm_kmemdup(&pdev->dev, sor->soc->settings, 2551 sor->settings = devm_kmemdup(&pdev->dev, sor->soc->settings,
2555 sor->soc->num_settings * 2552 sor->soc->num_settings *
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c
index 2448229fa653..18024183aa2b 100644
--- a/drivers/gpu/drm/tegra/vic.c
+++ b/drivers/gpu/drm/tegra/vic.c
@@ -167,7 +167,7 @@ static int vic_init(struct host1x_client *client)
167 goto detach_device; 167 goto detach_device;
168 } 168 }
169 169
170 client->syncpts[0] = host1x_syncpt_request(client->dev, 0); 170 client->syncpts[0] = host1x_syncpt_request(client, 0);
171 if (!client->syncpts[0]) { 171 if (!client->syncpts[0]) {
172 err = -ENOMEM; 172 err = -ENOMEM;
173 goto free_channel; 173 goto free_channel;
@@ -270,29 +270,33 @@ static const struct vic_config vic_t210_config = {
270 .firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE, 270 .firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE,
271}; 271};
272 272
273#define NVIDIA_TEGRA_186_VIC_FIRMWARE "nvidia/tegra186/vic04_ucode.bin"
274
275static const struct vic_config vic_t186_config = {
276 .firmware = NVIDIA_TEGRA_186_VIC_FIRMWARE,
277};
278
273static const struct of_device_id vic_match[] = { 279static const struct of_device_id vic_match[] = {
274 { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config }, 280 { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config },
275 { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config }, 281 { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config },
282 { .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config },
276 { }, 283 { },
277}; 284};
278 285
279static int vic_probe(struct platform_device *pdev) 286static int vic_probe(struct platform_device *pdev)
280{ 287{
281 struct vic_config *vic_config = NULL;
282 struct device *dev = &pdev->dev; 288 struct device *dev = &pdev->dev;
283 struct host1x_syncpt **syncpts; 289 struct host1x_syncpt **syncpts;
284 struct resource *regs; 290 struct resource *regs;
285 const struct of_device_id *match;
286 struct vic *vic; 291 struct vic *vic;
287 int err; 292 int err;
288 293
289 match = of_match_device(vic_match, dev);
290 vic_config = (struct vic_config *)match->data;
291
292 vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL); 294 vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL);
293 if (!vic) 295 if (!vic)
294 return -ENOMEM; 296 return -ENOMEM;
295 297
298 vic->config = of_device_get_match_data(dev);
299
296 syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); 300 syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
297 if (!syncpts) 301 if (!syncpts)
298 return -ENOMEM; 302 return -ENOMEM;
@@ -321,7 +325,7 @@ static int vic_probe(struct platform_device *pdev)
321 if (err < 0) 325 if (err < 0)
322 return err; 326 return err;
323 327
324 err = falcon_read_firmware(&vic->falcon, vic_config->firmware); 328 err = falcon_read_firmware(&vic->falcon, vic->config->firmware);
325 if (err < 0) 329 if (err < 0)
326 goto exit_falcon; 330 goto exit_falcon;
327 331
@@ -334,7 +338,6 @@ static int vic_probe(struct platform_device *pdev)
334 vic->client.base.syncpts = syncpts; 338 vic->client.base.syncpts = syncpts;
335 vic->client.base.num_syncpts = 1; 339 vic->client.base.num_syncpts = 1;
336 vic->dev = dev; 340 vic->dev = dev;
337 vic->config = vic_config;
338 341
339 INIT_LIST_HEAD(&vic->client.list); 342 INIT_LIST_HEAD(&vic->client.list);
340 vic->client.ops = &vic_ops; 343 vic->client.ops = &vic_ops;
@@ -405,3 +408,6 @@ MODULE_FIRMWARE(NVIDIA_TEGRA_124_VIC_FIRMWARE);
405#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) 408#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
406MODULE_FIRMWARE(NVIDIA_TEGRA_210_VIC_FIRMWARE); 409MODULE_FIRMWARE(NVIDIA_TEGRA_210_VIC_FIRMWARE);
407#endif 410#endif
411#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
412MODULE_FIRMWARE(NVIDIA_TEGRA_186_VIC_FIRMWARE);
413#endif
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile
index a1d9974cfcb5..4fb61bd57aee 100644
--- a/drivers/gpu/host1x/Makefile
+++ b/drivers/gpu/host1x/Makefile
@@ -11,6 +11,7 @@ host1x-y = \
11 hw/host1x01.o \ 11 hw/host1x01.o \
12 hw/host1x02.o \ 12 hw/host1x02.o \
13 hw/host1x04.o \ 13 hw/host1x04.o \
14 hw/host1x05.o 14 hw/host1x05.o \
15 hw/host1x06.o
15 16
16obj-$(CONFIG_TEGRA_HOST1X) += host1x.o 17obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index f9cde03030fd..66ea5acee820 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -403,12 +403,13 @@ static int host1x_device_add(struct host1x *host1x,
403 device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask; 403 device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
404 device->dev.dma_mask = &device->dev.coherent_dma_mask; 404 device->dev.dma_mask = &device->dev.coherent_dma_mask;
405 dev_set_name(&device->dev, "%s", driver->driver.name); 405 dev_set_name(&device->dev, "%s", driver->driver.name);
406 of_dma_configure(&device->dev, host1x->dev->of_node);
407 device->dev.release = host1x_device_release; 406 device->dev.release = host1x_device_release;
408 device->dev.of_node = host1x->dev->of_node; 407 device->dev.of_node = host1x->dev->of_node;
409 device->dev.bus = &host1x_bus_type; 408 device->dev.bus = &host1x_bus_type;
410 device->dev.parent = host1x->dev; 409 device->dev.parent = host1x->dev;
411 410
411 of_dma_configure(&device->dev, host1x->dev->of_node);
412
412 err = host1x_device_parse_dt(device, driver); 413 err = host1x_device_parse_dt(device, driver);
413 if (err < 0) { 414 if (err < 0) {
414 kfree(device); 415 kfree(device);
diff --git a/drivers/gpu/host1x/channel.c b/drivers/gpu/host1x/channel.c
index db9b91d1384c..2fb93c27c1d9 100644
--- a/drivers/gpu/host1x/channel.c
+++ b/drivers/gpu/host1x/channel.c
@@ -128,8 +128,7 @@ static struct host1x_channel *acquire_unused_channel(struct host1x *host)
128 * host1x_channel_request() - Allocate a channel 128 * host1x_channel_request() - Allocate a channel
129 * @device: Host1x unit this channel will be used to send commands to 129 * @device: Host1x unit this channel will be used to send commands to
130 * 130 *
131 * Allocates a new host1x channel for @device. If there are no free channels, 131 * Allocates a new host1x channel for @device. May return NULL if CDMA
132 * this will sleep until one becomes available. May return NULL if CDMA
133 * initialization fails. 132 * initialization fails.
134 */ 133 */
135struct host1x_channel *host1x_channel_request(struct device *dev) 134struct host1x_channel *host1x_channel_request(struct device *dev)
diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c
index 2aae0e63214c..dc77ec452ffc 100644
--- a/drivers/gpu/host1x/debug.c
+++ b/drivers/gpu/host1x/debug.c
@@ -40,7 +40,19 @@ void host1x_debug_output(struct output *o, const char *fmt, ...)
40 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); 40 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
41 va_end(args); 41 va_end(args);
42 42
43 o->fn(o->ctx, o->buf, len); 43 o->fn(o->ctx, o->buf, len, false);
44}
45
46void host1x_debug_cont(struct output *o, const char *fmt, ...)
47{
48 va_list args;
49 int len;
50
51 va_start(args, fmt);
52 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
53 va_end(args);
54
55 o->fn(o->ctx, o->buf, len, true);
44} 56}
45 57
46static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) 58static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
diff --git a/drivers/gpu/host1x/debug.h b/drivers/gpu/host1x/debug.h
index 4595b2e0799f..990cce47e737 100644
--- a/drivers/gpu/host1x/debug.h
+++ b/drivers/gpu/host1x/debug.h
@@ -24,22 +24,28 @@
24struct host1x; 24struct host1x;
25 25
26struct output { 26struct output {
27 void (*fn)(void *ctx, const char *str, size_t len); 27 void (*fn)(void *ctx, const char *str, size_t len, bool cont);
28 void *ctx; 28 void *ctx;
29 char buf[256]; 29 char buf[256];
30}; 30};
31 31
32static inline void write_to_seqfile(void *ctx, const char *str, size_t len) 32static inline void write_to_seqfile(void *ctx, const char *str, size_t len,
33 bool cont)
33{ 34{
34 seq_write((struct seq_file *)ctx, str, len); 35 seq_write((struct seq_file *)ctx, str, len);
35} 36}
36 37
37static inline void write_to_printk(void *ctx, const char *str, size_t len) 38static inline void write_to_printk(void *ctx, const char *str, size_t len,
39 bool cont)
38{ 40{
39 pr_info("%s", str); 41 if (cont)
42 pr_cont("%s", str);
43 else
44 pr_info("%s", str);
40} 45}
41 46
42void __printf(2, 3) host1x_debug_output(struct output *o, const char *fmt, ...); 47void __printf(2, 3) host1x_debug_output(struct output *o, const char *fmt, ...);
48void __printf(2, 3) host1x_debug_cont(struct output *o, const char *fmt, ...);
43 49
44extern unsigned int host1x_debug_trace_cmdbuf; 50extern unsigned int host1x_debug_trace_cmdbuf;
45 51
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 7f22c5c37660..773d6337aa30 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -39,6 +39,17 @@
39#include "hw/host1x02.h" 39#include "hw/host1x02.h"
40#include "hw/host1x04.h" 40#include "hw/host1x04.h"
41#include "hw/host1x05.h" 41#include "hw/host1x05.h"
42#include "hw/host1x06.h"
43
44void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r)
45{
46 writel(v, host1x->hv_regs + r);
47}
48
49u32 host1x_hypervisor_readl(struct host1x *host1x, u32 r)
50{
51 return readl(host1x->hv_regs + r);
52}
42 53
43void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) 54void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
44{ 55{
@@ -104,7 +115,19 @@ static const struct host1x_info host1x05_info = {
104 .dma_mask = DMA_BIT_MASK(34), 115 .dma_mask = DMA_BIT_MASK(34),
105}; 116};
106 117
118static const struct host1x_info host1x06_info = {
119 .nb_channels = 63,
120 .nb_pts = 576,
121 .nb_mlocks = 24,
122 .nb_bases = 16,
123 .init = host1x06_init,
124 .sync_offset = 0x0,
125 .dma_mask = DMA_BIT_MASK(34),
126 .has_hypervisor = true,
127};
128
107static const struct of_device_id host1x_of_match[] = { 129static const struct of_device_id host1x_of_match[] = {
130 { .compatible = "nvidia,tegra186-host1x", .data = &host1x06_info, },
108 { .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, }, 131 { .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, },
109 { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, }, 132 { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, },
110 { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, }, 133 { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, },
@@ -116,20 +139,37 @@ MODULE_DEVICE_TABLE(of, host1x_of_match);
116 139
117static int host1x_probe(struct platform_device *pdev) 140static int host1x_probe(struct platform_device *pdev)
118{ 141{
119 const struct of_device_id *id;
120 struct host1x *host; 142 struct host1x *host;
121 struct resource *regs; 143 struct resource *regs, *hv_regs = NULL;
122 int syncpt_irq; 144 int syncpt_irq;
123 int err; 145 int err;
124 146
125 id = of_match_device(host1x_of_match, &pdev->dev); 147 host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
126 if (!id) 148 if (!host)
127 return -EINVAL; 149 return -ENOMEM;
128 150
129 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 151 host->info = of_device_get_match_data(&pdev->dev);
130 if (!regs) { 152
131 dev_err(&pdev->dev, "failed to get registers\n"); 153 if (host->info->has_hypervisor) {
132 return -ENXIO; 154 regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vm");
155 if (!regs) {
156 dev_err(&pdev->dev, "failed to get vm registers\n");
157 return -ENXIO;
158 }
159
160 hv_regs = platform_get_resource_byname(pdev, IORESOURCE_MEM,
161 "hypervisor");
162 if (!hv_regs) {
163 dev_err(&pdev->dev,
164 "failed to get hypervisor registers\n");
165 return -ENXIO;
166 }
167 } else {
168 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
169 if (!regs) {
170 dev_err(&pdev->dev, "failed to get registers\n");
171 return -ENXIO;
172 }
133 } 173 }
134 174
135 syncpt_irq = platform_get_irq(pdev, 0); 175 syncpt_irq = platform_get_irq(pdev, 0);
@@ -138,15 +178,10 @@ static int host1x_probe(struct platform_device *pdev)
138 return syncpt_irq; 178 return syncpt_irq;
139 } 179 }
140 180
141 host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
142 if (!host)
143 return -ENOMEM;
144
145 mutex_init(&host->devices_lock); 181 mutex_init(&host->devices_lock);
146 INIT_LIST_HEAD(&host->devices); 182 INIT_LIST_HEAD(&host->devices);
147 INIT_LIST_HEAD(&host->list); 183 INIT_LIST_HEAD(&host->list);
148 host->dev = &pdev->dev; 184 host->dev = &pdev->dev;
149 host->info = id->data;
150 185
151 /* set common host1x device data */ 186 /* set common host1x device data */
152 platform_set_drvdata(pdev, host); 187 platform_set_drvdata(pdev, host);
@@ -155,6 +190,12 @@ static int host1x_probe(struct platform_device *pdev)
155 if (IS_ERR(host->regs)) 190 if (IS_ERR(host->regs))
156 return PTR_ERR(host->regs); 191 return PTR_ERR(host->regs);
157 192
193 if (host->info->has_hypervisor) {
194 host->hv_regs = devm_ioremap_resource(&pdev->dev, hv_regs);
195 if (IS_ERR(host->hv_regs))
196 return PTR_ERR(host->hv_regs);
197 }
198
158 dma_set_mask_and_coherent(host->dev, host->info->dma_mask); 199 dma_set_mask_and_coherent(host->dev, host->info->dma_mask);
159 200
160 if (host->info->init) { 201 if (host->info->init) {
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h
index ffdbc15b749b..502769726480 100644
--- a/drivers/gpu/host1x/dev.h
+++ b/drivers/gpu/host1x/dev.h
@@ -79,6 +79,9 @@ struct host1x_syncpt_ops {
79 u32 (*load)(struct host1x_syncpt *syncpt); 79 u32 (*load)(struct host1x_syncpt *syncpt);
80 int (*cpu_incr)(struct host1x_syncpt *syncpt); 80 int (*cpu_incr)(struct host1x_syncpt *syncpt);
81 int (*patch_wait)(struct host1x_syncpt *syncpt, void *patch_addr); 81 int (*patch_wait)(struct host1x_syncpt *syncpt, void *patch_addr);
82 void (*assign_to_channel)(struct host1x_syncpt *syncpt,
83 struct host1x_channel *channel);
84 void (*enable_protection)(struct host1x *host);
82}; 85};
83 86
84struct host1x_intr_ops { 87struct host1x_intr_ops {
@@ -100,12 +103,14 @@ struct host1x_info {
100 int (*init)(struct host1x *host1x); /* initialize per SoC ops */ 103 int (*init)(struct host1x *host1x); /* initialize per SoC ops */
101 unsigned int sync_offset; /* offset of syncpoint registers */ 104 unsigned int sync_offset; /* offset of syncpoint registers */
102 u64 dma_mask; /* mask of addressable memory */ 105 u64 dma_mask; /* mask of addressable memory */
106 bool has_hypervisor; /* has hypervisor registers */
103}; 107};
104 108
105struct host1x { 109struct host1x {
106 const struct host1x_info *info; 110 const struct host1x_info *info;
107 111
108 void __iomem *regs; 112 void __iomem *regs;
113 void __iomem *hv_regs; /* hypervisor region */
109 struct host1x_syncpt *syncpt; 114 struct host1x_syncpt *syncpt;
110 struct host1x_syncpt_base *bases; 115 struct host1x_syncpt_base *bases;
111 struct device *dev; 116 struct device *dev;
@@ -140,6 +145,8 @@ struct host1x {
140 struct list_head list; 145 struct list_head list;
141}; 146};
142 147
148void host1x_hypervisor_writel(struct host1x *host1x, u32 r, u32 v);
149u32 host1x_hypervisor_readl(struct host1x *host1x, u32 r);
143void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); 150void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v);
144u32 host1x_sync_readl(struct host1x *host1x, u32 r); 151u32 host1x_sync_readl(struct host1x *host1x, u32 r);
145void host1x_ch_writel(struct host1x_channel *ch, u32 r, u32 v); 152void host1x_ch_writel(struct host1x_channel *ch, u32 r, u32 v);
@@ -182,6 +189,18 @@ static inline int host1x_hw_syncpt_patch_wait(struct host1x *host,
182 return host->syncpt_op->patch_wait(sp, patch_addr); 189 return host->syncpt_op->patch_wait(sp, patch_addr);
183} 190}
184 191
192static inline void host1x_hw_syncpt_assign_to_channel(
193 struct host1x *host, struct host1x_syncpt *sp,
194 struct host1x_channel *ch)
195{
196 return host->syncpt_op->assign_to_channel(sp, ch);
197}
198
199static inline void host1x_hw_syncpt_enable_protection(struct host1x *host)
200{
201 return host->syncpt_op->enable_protection(host);
202}
203
185static inline int host1x_hw_intr_init_host_sync(struct host1x *host, u32 cpm, 204static inline int host1x_hw_intr_init_host_sync(struct host1x *host, u32 cpm,
186 void (*syncpt_thresh_work)(struct work_struct *)) 205 void (*syncpt_thresh_work)(struct work_struct *))
187{ 206{
diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c
index 6b231119193e..ce320534cbed 100644
--- a/drivers/gpu/host1x/hw/cdma_hw.c
+++ b/drivers/gpu/host1x/hw/cdma_hw.c
@@ -172,6 +172,30 @@ static void cdma_stop(struct host1x_cdma *cdma)
172 mutex_unlock(&cdma->lock); 172 mutex_unlock(&cdma->lock);
173} 173}
174 174
175static void cdma_hw_cmdproc_stop(struct host1x *host, struct host1x_channel *ch,
176 bool stop)
177{
178#if HOST1X_HW >= 6
179 host1x_ch_writel(ch, stop ? 0x1 : 0x0, HOST1X_CHANNEL_CMDPROC_STOP);
180#else
181 u32 cmdproc_stop = host1x_sync_readl(host, HOST1X_SYNC_CMDPROC_STOP);
182 if (stop)
183 cmdproc_stop |= BIT(ch->id);
184 else
185 cmdproc_stop &= ~BIT(ch->id);
186 host1x_sync_writel(host, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP);
187#endif
188}
189
190static void cdma_hw_teardown(struct host1x *host, struct host1x_channel *ch)
191{
192#if HOST1X_HW >= 6
193 host1x_ch_writel(ch, 0x1, HOST1X_CHANNEL_TEARDOWN);
194#else
195 host1x_sync_writel(host, BIT(ch->id), HOST1X_SYNC_CH_TEARDOWN);
196#endif
197}
198
175/* 199/*
176 * Stops both channel's command processor and CDMA immediately. 200 * Stops both channel's command processor and CDMA immediately.
177 * Also, tears down the channel and resets corresponding module. 201 * Also, tears down the channel and resets corresponding module.
@@ -180,7 +204,6 @@ static void cdma_freeze(struct host1x_cdma *cdma)
180{ 204{
181 struct host1x *host = cdma_to_host1x(cdma); 205 struct host1x *host = cdma_to_host1x(cdma);
182 struct host1x_channel *ch = cdma_to_channel(cdma); 206 struct host1x_channel *ch = cdma_to_channel(cdma);
183 u32 cmdproc_stop;
184 207
185 if (cdma->torndown && !cdma->running) { 208 if (cdma->torndown && !cdma->running) {
186 dev_warn(host->dev, "Already torn down\n"); 209 dev_warn(host->dev, "Already torn down\n");
@@ -189,9 +212,7 @@ static void cdma_freeze(struct host1x_cdma *cdma)
189 212
190 dev_dbg(host->dev, "freezing channel (id %d)\n", ch->id); 213 dev_dbg(host->dev, "freezing channel (id %d)\n", ch->id);
191 214
192 cmdproc_stop = host1x_sync_readl(host, HOST1X_SYNC_CMDPROC_STOP); 215 cdma_hw_cmdproc_stop(host, ch, true);
193 cmdproc_stop |= BIT(ch->id);
194 host1x_sync_writel(host, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP);
195 216
196 dev_dbg(host->dev, "%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n", 217 dev_dbg(host->dev, "%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n",
197 __func__, host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET), 218 __func__, host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET),
@@ -201,7 +222,7 @@ static void cdma_freeze(struct host1x_cdma *cdma)
201 host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, 222 host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP,
202 HOST1X_CHANNEL_DMACTRL); 223 HOST1X_CHANNEL_DMACTRL);
203 224
204 host1x_sync_writel(host, BIT(ch->id), HOST1X_SYNC_CH_TEARDOWN); 225 cdma_hw_teardown(host, ch);
205 226
206 cdma->running = false; 227 cdma->running = false;
207 cdma->torndown = true; 228 cdma->torndown = true;
@@ -211,15 +232,12 @@ static void cdma_resume(struct host1x_cdma *cdma, u32 getptr)
211{ 232{
212 struct host1x *host1x = cdma_to_host1x(cdma); 233 struct host1x *host1x = cdma_to_host1x(cdma);
213 struct host1x_channel *ch = cdma_to_channel(cdma); 234 struct host1x_channel *ch = cdma_to_channel(cdma);
214 u32 cmdproc_stop;
215 235
216 dev_dbg(host1x->dev, 236 dev_dbg(host1x->dev,
217 "resuming channel (id %u, DMAGET restart = 0x%x)\n", 237 "resuming channel (id %u, DMAGET restart = 0x%x)\n",
218 ch->id, getptr); 238 ch->id, getptr);
219 239
220 cmdproc_stop = host1x_sync_readl(host1x, HOST1X_SYNC_CMDPROC_STOP); 240 cdma_hw_cmdproc_stop(host1x, ch, false);
221 cmdproc_stop &= ~BIT(ch->id);
222 host1x_sync_writel(host1x, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP);
223 241
224 cdma->torndown = false; 242 cdma->torndown = false;
225 cdma_timeout_restart(cdma, getptr); 243 cdma_timeout_restart(cdma, getptr);
@@ -232,7 +250,7 @@ static void cdma_resume(struct host1x_cdma *cdma, u32 getptr)
232 */ 250 */
233static void cdma_timeout_handler(struct work_struct *work) 251static void cdma_timeout_handler(struct work_struct *work)
234{ 252{
235 u32 prev_cmdproc, cmdproc_stop, syncpt_val; 253 u32 syncpt_val;
236 struct host1x_cdma *cdma; 254 struct host1x_cdma *cdma;
237 struct host1x *host1x; 255 struct host1x *host1x;
238 struct host1x_channel *ch; 256 struct host1x_channel *ch;
@@ -254,12 +272,7 @@ static void cdma_timeout_handler(struct work_struct *work)
254 } 272 }
255 273
256 /* stop processing to get a clean snapshot */ 274 /* stop processing to get a clean snapshot */
257 prev_cmdproc = host1x_sync_readl(host1x, HOST1X_SYNC_CMDPROC_STOP); 275 cdma_hw_cmdproc_stop(host1x, ch, true);
258 cmdproc_stop = prev_cmdproc | BIT(ch->id);
259 host1x_sync_writel(host1x, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP);
260
261 dev_dbg(host1x->dev, "cdma_timeout: cmdproc was 0x%x is 0x%x\n",
262 prev_cmdproc, cmdproc_stop);
263 276
264 syncpt_val = host1x_syncpt_load(cdma->timeout.syncpt); 277 syncpt_val = host1x_syncpt_load(cdma->timeout.syncpt);
265 278
@@ -268,9 +281,7 @@ static void cdma_timeout_handler(struct work_struct *work)
268 dev_dbg(host1x->dev, 281 dev_dbg(host1x->dev,
269 "cdma_timeout: expired, but buffer had completed\n"); 282 "cdma_timeout: expired, but buffer had completed\n");
270 /* restore */ 283 /* restore */
271 cmdproc_stop = prev_cmdproc & ~(BIT(ch->id)); 284 cdma_hw_cmdproc_stop(host1x, ch, false);
272 host1x_sync_writel(host1x, cmdproc_stop,
273 HOST1X_SYNC_CMDPROC_STOP);
274 mutex_unlock(&cdma->lock); 285 mutex_unlock(&cdma->lock);
275 return; 286 return;
276 } 287 }
diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c
index 8447a56c41ca..9af758785a11 100644
--- a/drivers/gpu/host1x/hw/channel_hw.c
+++ b/drivers/gpu/host1x/hw/channel_hw.c
@@ -147,6 +147,8 @@ static int channel_submit(struct host1x_job *job)
147 147
148 syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs); 148 syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs);
149 149
150 host1x_hw_syncpt_assign_to_channel(host, sp, ch);
151
150 job->syncpt_end = syncval; 152 job->syncpt_end = syncval;
151 153
152 /* add a setclass for modules that require it */ 154 /* add a setclass for modules that require it */
@@ -178,10 +180,32 @@ error:
178 return err; 180 return err;
179} 181}
180 182
183static void enable_gather_filter(struct host1x *host,
184 struct host1x_channel *ch)
185{
186#if HOST1X_HW >= 6
187 u32 val;
188
189 if (!host->hv_regs)
190 return;
191
192 val = host1x_hypervisor_readl(
193 host, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32));
194 val |= BIT(ch->id % 32);
195 host1x_hypervisor_writel(
196 host, val, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32));
197#elif HOST1X_HW >= 4
198 host1x_ch_writel(ch,
199 HOST1X_CHANNEL_CHANNELCTRL_KERNEL_FILTER_GBUFFER(1),
200 HOST1X_CHANNEL_CHANNELCTRL);
201#endif
202}
203
181static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev, 204static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev,
182 unsigned int index) 205 unsigned int index)
183{ 206{
184 ch->regs = dev->regs + index * HOST1X_CHANNEL_SIZE; 207 ch->regs = dev->regs + index * HOST1X_CHANNEL_SIZE;
208 enable_gather_filter(dev, ch);
185 return 0; 209 return 0;
186} 210}
187 211
diff --git a/drivers/gpu/host1x/hw/debug_hw.c b/drivers/gpu/host1x/hw/debug_hw.c
index 7a4a3286e4a7..989476801f9d 100644
--- a/drivers/gpu/host1x/hw/debug_hw.c
+++ b/drivers/gpu/host1x/hw/debug_hw.c
@@ -30,6 +30,13 @@ enum {
30 HOST1X_OPCODE_IMM = 0x04, 30 HOST1X_OPCODE_IMM = 0x04,
31 HOST1X_OPCODE_RESTART = 0x05, 31 HOST1X_OPCODE_RESTART = 0x05,
32 HOST1X_OPCODE_GATHER = 0x06, 32 HOST1X_OPCODE_GATHER = 0x06,
33 HOST1X_OPCODE_SETSTRMID = 0x07,
34 HOST1X_OPCODE_SETAPPID = 0x08,
35 HOST1X_OPCODE_SETPYLD = 0x09,
36 HOST1X_OPCODE_INCR_W = 0x0a,
37 HOST1X_OPCODE_NONINCR_W = 0x0b,
38 HOST1X_OPCODE_GATHER_W = 0x0c,
39 HOST1X_OPCODE_RESTART_W = 0x0d,
33 HOST1X_OPCODE_EXTEND = 0x0e, 40 HOST1X_OPCODE_EXTEND = 0x0e,
34}; 41};
35 42
@@ -38,67 +45,122 @@ enum {
38 HOST1X_OPCODE_EXTEND_RELEASE_MLOCK = 0x01, 45 HOST1X_OPCODE_EXTEND_RELEASE_MLOCK = 0x01,
39}; 46};
40 47
41static unsigned int show_channel_command(struct output *o, u32 val) 48#define INVALID_PAYLOAD 0xffffffff
49
50static unsigned int show_channel_command(struct output *o, u32 val,
51 u32 *payload)
42{ 52{
43 unsigned int mask, subop; 53 unsigned int mask, subop, num, opcode;
54
55 opcode = val >> 28;
44 56
45 switch (val >> 28) { 57 switch (opcode) {
46 case HOST1X_OPCODE_SETCLASS: 58 case HOST1X_OPCODE_SETCLASS:
47 mask = val & 0x3f; 59 mask = val & 0x3f;
48 if (mask) { 60 if (mask) {
49 host1x_debug_output(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [", 61 host1x_debug_cont(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [",
50 val >> 6 & 0x3ff, 62 val >> 6 & 0x3ff,
51 val >> 16 & 0xfff, mask); 63 val >> 16 & 0xfff, mask);
52 return hweight8(mask); 64 return hweight8(mask);
53 } 65 }
54 66
55 host1x_debug_output(o, "SETCL(class=%03x)\n", val >> 6 & 0x3ff); 67 host1x_debug_cont(o, "SETCL(class=%03x)\n", val >> 6 & 0x3ff);
56 return 0; 68 return 0;
57 69
58 case HOST1X_OPCODE_INCR: 70 case HOST1X_OPCODE_INCR:
59 host1x_debug_output(o, "INCR(offset=%03x, [", 71 num = val & 0xffff;
72 host1x_debug_cont(o, "INCR(offset=%03x, [",
60 val >> 16 & 0xfff); 73 val >> 16 & 0xfff);
61 return val & 0xffff; 74 if (!num)
75 host1x_debug_cont(o, "])\n");
76
77 return num;
62 78
63 case HOST1X_OPCODE_NONINCR: 79 case HOST1X_OPCODE_NONINCR:
64 host1x_debug_output(o, "NONINCR(offset=%03x, [", 80 num = val & 0xffff;
81 host1x_debug_cont(o, "NONINCR(offset=%03x, [",
65 val >> 16 & 0xfff); 82 val >> 16 & 0xfff);
66 return val & 0xffff; 83 if (!num)
84 host1x_debug_cont(o, "])\n");
85
86 return num;
67 87
68 case HOST1X_OPCODE_MASK: 88 case HOST1X_OPCODE_MASK:
69 mask = val & 0xffff; 89 mask = val & 0xffff;
70 host1x_debug_output(o, "MASK(offset=%03x, mask=%03x, [", 90 host1x_debug_cont(o, "MASK(offset=%03x, mask=%03x, [",
71 val >> 16 & 0xfff, mask); 91 val >> 16 & 0xfff, mask);
92 if (!mask)
93 host1x_debug_cont(o, "])\n");
94
72 return hweight16(mask); 95 return hweight16(mask);
73 96
74 case HOST1X_OPCODE_IMM: 97 case HOST1X_OPCODE_IMM:
75 host1x_debug_output(o, "IMM(offset=%03x, data=%03x)\n", 98 host1x_debug_cont(o, "IMM(offset=%03x, data=%03x)\n",
76 val >> 16 & 0xfff, val & 0xffff); 99 val >> 16 & 0xfff, val & 0xffff);
77 return 0; 100 return 0;
78 101
79 case HOST1X_OPCODE_RESTART: 102 case HOST1X_OPCODE_RESTART:
80 host1x_debug_output(o, "RESTART(offset=%08x)\n", val << 4); 103 host1x_debug_cont(o, "RESTART(offset=%08x)\n", val << 4);
81 return 0; 104 return 0;
82 105
83 case HOST1X_OPCODE_GATHER: 106 case HOST1X_OPCODE_GATHER:
84 host1x_debug_output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[", 107 host1x_debug_cont(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
85 val >> 16 & 0xfff, val >> 15 & 0x1, 108 val >> 16 & 0xfff, val >> 15 & 0x1,
86 val >> 14 & 0x1, val & 0x3fff); 109 val >> 14 & 0x1, val & 0x3fff);
87 return 1; 110 return 1;
88 111
112#if HOST1X_HW >= 6
113 case HOST1X_OPCODE_SETSTRMID:
114 host1x_debug_cont(o, "SETSTRMID(offset=%06x)\n",
115 val & 0x3fffff);
116 return 0;
117
118 case HOST1X_OPCODE_SETAPPID:
119 host1x_debug_cont(o, "SETAPPID(appid=%02x)\n", val & 0xff);
120 return 0;
121
122 case HOST1X_OPCODE_SETPYLD:
123 *payload = val & 0xffff;
124 host1x_debug_cont(o, "SETPYLD(data=%04x)\n", *payload);
125 return 0;
126
127 case HOST1X_OPCODE_INCR_W:
128 case HOST1X_OPCODE_NONINCR_W:
129 host1x_debug_cont(o, "%s(offset=%06x, ",
130 opcode == HOST1X_OPCODE_INCR_W ?
131 "INCR_W" : "NONINCR_W",
132 val & 0x3fffff);
133 if (*payload == 0) {
134 host1x_debug_cont(o, "[])\n");
135 return 0;
136 } else if (*payload == INVALID_PAYLOAD) {
137 host1x_debug_cont(o, "unknown)\n");
138 return 0;
139 } else {
140 host1x_debug_cont(o, "[");
141 return *payload;
142 }
143
144 case HOST1X_OPCODE_GATHER_W:
145 host1x_debug_cont(o, "GATHER_W(count=%04x, addr=[",
146 val & 0x3fff);
147 return 2;
148#endif
149
89 case HOST1X_OPCODE_EXTEND: 150 case HOST1X_OPCODE_EXTEND:
90 subop = val >> 24 & 0xf; 151 subop = val >> 24 & 0xf;
91 if (subop == HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK) 152 if (subop == HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK)
92 host1x_debug_output(o, "ACQUIRE_MLOCK(index=%d)\n", 153 host1x_debug_cont(o, "ACQUIRE_MLOCK(index=%d)\n",
93 val & 0xff); 154 val & 0xff);
94 else if (subop == HOST1X_OPCODE_EXTEND_RELEASE_MLOCK) 155 else if (subop == HOST1X_OPCODE_EXTEND_RELEASE_MLOCK)
95 host1x_debug_output(o, "RELEASE_MLOCK(index=%d)\n", 156 host1x_debug_cont(o, "RELEASE_MLOCK(index=%d)\n",
96 val & 0xff); 157 val & 0xff);
97 else 158 else
98 host1x_debug_output(o, "EXTEND_UNKNOWN(%08x)\n", val); 159 host1x_debug_cont(o, "EXTEND_UNKNOWN(%08x)\n", val);
99 return 0; 160 return 0;
100 161
101 default: 162 default:
163 host1x_debug_cont(o, "UNKNOWN\n");
102 return 0; 164 return 0;
103 } 165 }
104} 166}
@@ -110,6 +172,7 @@ static void show_gather(struct output *o, phys_addr_t phys_addr,
110 /* Map dmaget cursor to corresponding mem handle */ 172 /* Map dmaget cursor to corresponding mem handle */
111 u32 offset = phys_addr - pin_addr; 173 u32 offset = phys_addr - pin_addr;
112 unsigned int data_count = 0, i; 174 unsigned int data_count = 0, i;
175 u32 payload = INVALID_PAYLOAD;
113 176
114 /* 177 /*
115 * Sometimes we're given different hardware address to the same 178 * Sometimes we're given different hardware address to the same
@@ -126,11 +189,11 @@ static void show_gather(struct output *o, phys_addr_t phys_addr,
126 u32 val = *(map_addr + offset / 4 + i); 189 u32 val = *(map_addr + offset / 4 + i);
127 190
128 if (!data_count) { 191 if (!data_count) {
129 host1x_debug_output(o, "%08x: %08x:", addr, val); 192 host1x_debug_output(o, "%08x: %08x: ", addr, val);
130 data_count = show_channel_command(o, val); 193 data_count = show_channel_command(o, val, &payload);
131 } else { 194 } else {
132 host1x_debug_output(o, "%08x%s", val, 195 host1x_debug_cont(o, "%08x%s", val,
133 data_count > 0 ? ", " : "])\n"); 196 data_count > 1 ? ", " : "])\n");
134 data_count--; 197 data_count--;
135 } 198 }
136 } 199 }
@@ -174,138 +237,11 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
174 } 237 }
175} 238}
176 239
177static void host1x_debug_show_channel_cdma(struct host1x *host, 240#if HOST1X_HW >= 6
178 struct host1x_channel *ch, 241#include "debug_hw_1x06.c"
179 struct output *o) 242#else
180{ 243#include "debug_hw_1x01.c"
181 struct host1x_cdma *cdma = &ch->cdma; 244#endif
182 u32 dmaput, dmaget, dmactrl;
183 u32 cbstat, cbread;
184 u32 val, base, baseval;
185
186 dmaput = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT);
187 dmaget = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET);
188 dmactrl = host1x_ch_readl(ch, HOST1X_CHANNEL_DMACTRL);
189 cbread = host1x_sync_readl(host, HOST1X_SYNC_CBREAD(ch->id));
190 cbstat = host1x_sync_readl(host, HOST1X_SYNC_CBSTAT(ch->id));
191
192 host1x_debug_output(o, "%u-%s: ", ch->id, dev_name(ch->dev));
193
194 if (HOST1X_CHANNEL_DMACTRL_DMASTOP_V(dmactrl) ||
195 !ch->cdma.push_buffer.mapped) {
196 host1x_debug_output(o, "inactive\n\n");
197 return;
198 }
199
200 if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == HOST1X_CLASS_HOST1X &&
201 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) ==
202 HOST1X_UCLASS_WAIT_SYNCPT)
203 host1x_debug_output(o, "waiting on syncpt %d val %d\n",
204 cbread >> 24, cbread & 0xffffff);
205 else if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) ==
206 HOST1X_CLASS_HOST1X &&
207 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) ==
208 HOST1X_UCLASS_WAIT_SYNCPT_BASE) {
209 base = (cbread >> 16) & 0xff;
210 baseval =
211 host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(base));
212 val = cbread & 0xffff;
213 host1x_debug_output(o, "waiting on syncpt %d val %d (base %d = %d; offset = %d)\n",
214 cbread >> 24, baseval + val, base,
215 baseval, val);
216 } else
217 host1x_debug_output(o, "active class %02x, offset %04x, val %08x\n",
218 HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat),
219 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat),
220 cbread);
221
222 host1x_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n",
223 dmaput, dmaget, dmactrl);
224 host1x_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat);
225
226 show_channel_gathers(o, cdma);
227 host1x_debug_output(o, "\n");
228}
229
230static void host1x_debug_show_channel_fifo(struct host1x *host,
231 struct host1x_channel *ch,
232 struct output *o)
233{
234 u32 val, rd_ptr, wr_ptr, start, end;
235 unsigned int data_count = 0;
236
237 host1x_debug_output(o, "%u: fifo:\n", ch->id);
238
239 val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT);
240 host1x_debug_output(o, "FIFOSTAT %08x\n", val);
241 if (HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(val)) {
242 host1x_debug_output(o, "[empty]\n");
243 return;
244 }
245
246 host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL);
247 host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) |
248 HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id),
249 HOST1X_SYNC_CFPEEK_CTRL);
250
251 val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_PTRS);
252 rd_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(val);
253 wr_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(val);
254
255 val = host1x_sync_readl(host, HOST1X_SYNC_CF_SETUP(ch->id));
256 start = HOST1X_SYNC_CF_SETUP_BASE_V(val);
257 end = HOST1X_SYNC_CF_SETUP_LIMIT_V(val);
258
259 do {
260 host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL);
261 host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) |
262 HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id) |
263 HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(rd_ptr),
264 HOST1X_SYNC_CFPEEK_CTRL);
265 val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_READ);
266
267 if (!data_count) {
268 host1x_debug_output(o, "%08x:", val);
269 data_count = show_channel_command(o, val);
270 } else {
271 host1x_debug_output(o, "%08x%s", val,
272 data_count > 0 ? ", " : "])\n");
273 data_count--;
274 }
275
276 if (rd_ptr == end)
277 rd_ptr = start;
278 else
279 rd_ptr++;
280 } while (rd_ptr != wr_ptr);
281
282 if (data_count)
283 host1x_debug_output(o, ", ...])\n");
284 host1x_debug_output(o, "\n");
285
286 host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL);
287}
288
289static void host1x_debug_show_mlocks(struct host1x *host, struct output *o)
290{
291 unsigned int i;
292
293 host1x_debug_output(o, "---- mlocks ----\n");
294
295 for (i = 0; i < host1x_syncpt_nb_mlocks(host); i++) {
296 u32 owner =
297 host1x_sync_readl(host, HOST1X_SYNC_MLOCK_OWNER(i));
298 if (HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(owner))
299 host1x_debug_output(o, "%u: locked by channel %u\n",
300 i, HOST1X_SYNC_MLOCK_OWNER_CHID_V(owner));
301 else if (HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(owner))
302 host1x_debug_output(o, "%u: locked by cpu\n", i);
303 else
304 host1x_debug_output(o, "%u: unlocked\n", i);
305 }
306
307 host1x_debug_output(o, "\n");
308}
309 245
310static const struct host1x_debug_ops host1x_debug_ops = { 246static const struct host1x_debug_ops host1x_debug_ops = {
311 .show_channel_cdma = host1x_debug_show_channel_cdma, 247 .show_channel_cdma = host1x_debug_show_channel_cdma,
diff --git a/drivers/gpu/host1x/hw/debug_hw_1x01.c b/drivers/gpu/host1x/hw/debug_hw_1x01.c
new file mode 100644
index 000000000000..8790d5fd5f20
--- /dev/null
+++ b/drivers/gpu/host1x/hw/debug_hw_1x01.c
@@ -0,0 +1,154 @@
1/*
2 * Copyright (C) 2010 Google, Inc.
3 * Author: Erik Gilling <konkers@android.com>
4 *
5 * Copyright (C) 2011-2013 NVIDIA Corporation
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#include "../dev.h"
19#include "../debug.h"
20#include "../cdma.h"
21#include "../channel.h"
22
23static void host1x_debug_show_channel_cdma(struct host1x *host,
24 struct host1x_channel *ch,
25 struct output *o)
26{
27 struct host1x_cdma *cdma = &ch->cdma;
28 u32 dmaput, dmaget, dmactrl;
29 u32 cbstat, cbread;
30 u32 val, base, baseval;
31
32 dmaput = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT);
33 dmaget = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET);
34 dmactrl = host1x_ch_readl(ch, HOST1X_CHANNEL_DMACTRL);
35 cbread = host1x_sync_readl(host, HOST1X_SYNC_CBREAD(ch->id));
36 cbstat = host1x_sync_readl(host, HOST1X_SYNC_CBSTAT(ch->id));
37
38 host1x_debug_output(o, "%u-%s: ", ch->id, dev_name(ch->dev));
39
40 if (HOST1X_CHANNEL_DMACTRL_DMASTOP_V(dmactrl) ||
41 !ch->cdma.push_buffer.mapped) {
42 host1x_debug_output(o, "inactive\n\n");
43 return;
44 }
45
46 if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == HOST1X_CLASS_HOST1X &&
47 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) ==
48 HOST1X_UCLASS_WAIT_SYNCPT)
49 host1x_debug_output(o, "waiting on syncpt %d val %d\n",
50 cbread >> 24, cbread & 0xffffff);
51 else if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) ==
52 HOST1X_CLASS_HOST1X &&
53 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) ==
54 HOST1X_UCLASS_WAIT_SYNCPT_BASE) {
55 base = (cbread >> 16) & 0xff;
56 baseval =
57 host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(base));
58 val = cbread & 0xffff;
59 host1x_debug_output(o, "waiting on syncpt %d val %d (base %d = %d; offset = %d)\n",
60 cbread >> 24, baseval + val, base,
61 baseval, val);
62 } else
63 host1x_debug_output(o, "active class %02x, offset %04x, val %08x\n",
64 HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat),
65 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat),
66 cbread);
67
68 host1x_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n",
69 dmaput, dmaget, dmactrl);
70 host1x_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat);
71
72 show_channel_gathers(o, cdma);
73 host1x_debug_output(o, "\n");
74}
75
76static void host1x_debug_show_channel_fifo(struct host1x *host,
77 struct host1x_channel *ch,
78 struct output *o)
79{
80 u32 val, rd_ptr, wr_ptr, start, end;
81 unsigned int data_count = 0;
82
83 host1x_debug_output(o, "%u: fifo:\n", ch->id);
84
85 val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT);
86 host1x_debug_output(o, "FIFOSTAT %08x\n", val);
87 if (HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(val)) {
88 host1x_debug_output(o, "[empty]\n");
89 return;
90 }
91
92 host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL);
93 host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) |
94 HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id),
95 HOST1X_SYNC_CFPEEK_CTRL);
96
97 val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_PTRS);
98 rd_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(val);
99 wr_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(val);
100
101 val = host1x_sync_readl(host, HOST1X_SYNC_CF_SETUP(ch->id));
102 start = HOST1X_SYNC_CF_SETUP_BASE_V(val);
103 end = HOST1X_SYNC_CF_SETUP_LIMIT_V(val);
104
105 do {
106 host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL);
107 host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) |
108 HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id) |
109 HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(rd_ptr),
110 HOST1X_SYNC_CFPEEK_CTRL);
111 val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_READ);
112
113 if (!data_count) {
114 host1x_debug_output(o, "%08x: ", val);
115 data_count = show_channel_command(o, val, NULL);
116 } else {
117 host1x_debug_cont(o, "%08x%s", val,
118 data_count > 1 ? ", " : "])\n");
119 data_count--;
120 }
121
122 if (rd_ptr == end)
123 rd_ptr = start;
124 else
125 rd_ptr++;
126 } while (rd_ptr != wr_ptr);
127
128 if (data_count)
129 host1x_debug_cont(o, ", ...])\n");
130 host1x_debug_output(o, "\n");
131
132 host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL);
133}
134
135static void host1x_debug_show_mlocks(struct host1x *host, struct output *o)
136{
137 unsigned int i;
138
139 host1x_debug_output(o, "---- mlocks ----\n");
140
141 for (i = 0; i < host1x_syncpt_nb_mlocks(host); i++) {
142 u32 owner =
143 host1x_sync_readl(host, HOST1X_SYNC_MLOCK_OWNER(i));
144 if (HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(owner))
145 host1x_debug_output(o, "%u: locked by channel %u\n",
146 i, HOST1X_SYNC_MLOCK_OWNER_CHID_V(owner));
147 else if (HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(owner))
148 host1x_debug_output(o, "%u: locked by cpu\n", i);
149 else
150 host1x_debug_output(o, "%u: unlocked\n", i);
151 }
152
153 host1x_debug_output(o, "\n");
154}
diff --git a/drivers/gpu/host1x/hw/debug_hw_1x06.c b/drivers/gpu/host1x/hw/debug_hw_1x06.c
new file mode 100644
index 000000000000..b503c740c022
--- /dev/null
+++ b/drivers/gpu/host1x/hw/debug_hw_1x06.c
@@ -0,0 +1,135 @@
1/*
2 * Copyright (C) 2010 Google, Inc.
3 * Author: Erik Gilling <konkers@android.com>
4 *
5 * Copyright (C) 2011-2017 NVIDIA Corporation
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#include "../dev.h"
19#include "../debug.h"
20#include "../cdma.h"
21#include "../channel.h"
22
23static void host1x_debug_show_channel_cdma(struct host1x *host,
24 struct host1x_channel *ch,
25 struct output *o)
26{
27 struct host1x_cdma *cdma = &ch->cdma;
28 u32 dmaput, dmaget, dmactrl;
29 u32 offset, class;
30 u32 ch_stat;
31
32 dmaput = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT);
33 dmaget = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET);
34 dmactrl = host1x_ch_readl(ch, HOST1X_CHANNEL_DMACTRL);
35 offset = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDP_OFFSET);
36 class = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDP_CLASS);
37 ch_stat = host1x_ch_readl(ch, HOST1X_CHANNEL_CHANNELSTAT);
38
39 host1x_debug_output(o, "%u-%s: ", ch->id, dev_name(ch->dev));
40
41 if (dmactrl & HOST1X_CHANNEL_DMACTRL_DMASTOP ||
42 !ch->cdma.push_buffer.mapped) {
43 host1x_debug_output(o, "inactive\n\n");
44 return;
45 }
46
47 if (class == HOST1X_CLASS_HOST1X && offset == HOST1X_UCLASS_WAIT_SYNCPT)
48 host1x_debug_output(o, "waiting on syncpt\n");
49 else
50 host1x_debug_output(o, "active class %02x, offset %04x\n",
51 class, offset);
52
53 host1x_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n",
54 dmaput, dmaget, dmactrl);
55 host1x_debug_output(o, "CHANNELSTAT %02x\n", ch_stat);
56
57 show_channel_gathers(o, cdma);
58 host1x_debug_output(o, "\n");
59}
60
61static void host1x_debug_show_channel_fifo(struct host1x *host,
62 struct host1x_channel *ch,
63 struct output *o)
64{
65 u32 val, rd_ptr, wr_ptr, start, end;
66 u32 payload = INVALID_PAYLOAD;
67 unsigned int data_count = 0;
68
69 host1x_debug_output(o, "%u: fifo:\n", ch->id);
70
71 val = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDFIFO_STAT);
72 host1x_debug_output(o, "CMDFIFO_STAT %08x\n", val);
73 if (val & HOST1X_CHANNEL_CMDFIFO_STAT_EMPTY) {
74 host1x_debug_output(o, "[empty]\n");
75 return;
76 }
77
78 val = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDFIFO_RDATA);
79 host1x_debug_output(o, "CMDFIFO_RDATA %08x\n", val);
80
81 /* Peek pointer values are invalid during SLCG, so disable it */
82 host1x_hypervisor_writel(host, 0x1, HOST1X_HV_ICG_EN_OVERRIDE);
83
84 val = 0;
85 val |= HOST1X_HV_CMDFIFO_PEEK_CTRL_ENABLE;
86 val |= HOST1X_HV_CMDFIFO_PEEK_CTRL_CHANNEL(ch->id);
87 host1x_hypervisor_writel(host, val, HOST1X_HV_CMDFIFO_PEEK_CTRL);
88
89 val = host1x_hypervisor_readl(host, HOST1X_HV_CMDFIFO_PEEK_PTRS);
90 rd_ptr = HOST1X_HV_CMDFIFO_PEEK_PTRS_RD_PTR_V(val);
91 wr_ptr = HOST1X_HV_CMDFIFO_PEEK_PTRS_WR_PTR_V(val);
92
93 val = host1x_hypervisor_readl(host, HOST1X_HV_CMDFIFO_SETUP(ch->id));
94 start = HOST1X_HV_CMDFIFO_SETUP_BASE_V(val);
95 end = HOST1X_HV_CMDFIFO_SETUP_LIMIT_V(val);
96
97 do {
98 val = 0;
99 val |= HOST1X_HV_CMDFIFO_PEEK_CTRL_ENABLE;
100 val |= HOST1X_HV_CMDFIFO_PEEK_CTRL_CHANNEL(ch->id);
101 val |= HOST1X_HV_CMDFIFO_PEEK_CTRL_ADDR(rd_ptr);
102 host1x_hypervisor_writel(host, val,
103 HOST1X_HV_CMDFIFO_PEEK_CTRL);
104
105 val = host1x_hypervisor_readl(host,
106 HOST1X_HV_CMDFIFO_PEEK_READ);
107
108 if (!data_count) {
109 host1x_debug_output(o, "%03x 0x%08x: ",
110 rd_ptr - start, val);
111 data_count = show_channel_command(o, val, &payload);
112 } else {
113 host1x_debug_cont(o, "%08x%s", val,
114 data_count > 1 ? ", " : "])\n");
115 data_count--;
116 }
117
118 if (rd_ptr == end)
119 rd_ptr = start;
120 else
121 rd_ptr++;
122 } while (rd_ptr != wr_ptr);
123
124 if (data_count)
125 host1x_debug_cont(o, ", ...])\n");
126 host1x_debug_output(o, "\n");
127
128 host1x_hypervisor_writel(host, 0x0, HOST1X_HV_CMDFIFO_PEEK_CTRL);
129 host1x_hypervisor_writel(host, 0x0, HOST1X_HV_ICG_EN_OVERRIDE);
130}
131
132static void host1x_debug_show_mlocks(struct host1x *host, struct output *o)
133{
134 /* TODO */
135}
diff --git a/drivers/gpu/host1x/hw/host1x01.c b/drivers/gpu/host1x/hw/host1x01.c
index 859b73beb4d0..bb124f8b4af8 100644
--- a/drivers/gpu/host1x/hw/host1x01.c
+++ b/drivers/gpu/host1x/hw/host1x01.c
@@ -21,6 +21,8 @@
21#include "host1x01_hardware.h" 21#include "host1x01_hardware.h"
22 22
23/* include code */ 23/* include code */
24#define HOST1X_HW 1
25
24#include "cdma_hw.c" 26#include "cdma_hw.c"
25#include "channel_hw.c" 27#include "channel_hw.c"
26#include "debug_hw.c" 28#include "debug_hw.c"
diff --git a/drivers/gpu/host1x/hw/host1x02.c b/drivers/gpu/host1x/hw/host1x02.c
index 928946c2144b..c5f85dbedb98 100644
--- a/drivers/gpu/host1x/hw/host1x02.c
+++ b/drivers/gpu/host1x/hw/host1x02.c
@@ -21,6 +21,8 @@
21#include "host1x02_hardware.h" 21#include "host1x02_hardware.h"
22 22
23/* include code */ 23/* include code */
24#define HOST1X_HW 2
25
24#include "cdma_hw.c" 26#include "cdma_hw.c"
25#include "channel_hw.c" 27#include "channel_hw.c"
26#include "debug_hw.c" 28#include "debug_hw.c"
diff --git a/drivers/gpu/host1x/hw/host1x04.c b/drivers/gpu/host1x/hw/host1x04.c
index 8007c70fa9c4..f102a1a7743f 100644
--- a/drivers/gpu/host1x/hw/host1x04.c
+++ b/drivers/gpu/host1x/hw/host1x04.c
@@ -21,6 +21,8 @@
21#include "host1x04_hardware.h" 21#include "host1x04_hardware.h"
22 22
23/* include code */ 23/* include code */
24#define HOST1X_HW 4
25
24#include "cdma_hw.c" 26#include "cdma_hw.c"
25#include "channel_hw.c" 27#include "channel_hw.c"
26#include "debug_hw.c" 28#include "debug_hw.c"
diff --git a/drivers/gpu/host1x/hw/host1x05.c b/drivers/gpu/host1x/hw/host1x05.c
index 047097ce3bad..2b1239d6ec67 100644
--- a/drivers/gpu/host1x/hw/host1x05.c
+++ b/drivers/gpu/host1x/hw/host1x05.c
@@ -21,6 +21,8 @@
21#include "host1x05_hardware.h" 21#include "host1x05_hardware.h"
22 22
23/* include code */ 23/* include code */
24#define HOST1X_HW 5
25
24#include "cdma_hw.c" 26#include "cdma_hw.c"
25#include "channel_hw.c" 27#include "channel_hw.c"
26#include "debug_hw.c" 28#include "debug_hw.c"
diff --git a/drivers/gpu/host1x/hw/host1x06.c b/drivers/gpu/host1x/hw/host1x06.c
new file mode 100644
index 000000000000..a66230827c59
--- /dev/null
+++ b/drivers/gpu/host1x/hw/host1x06.c
@@ -0,0 +1,44 @@
1/*
2 * Host1x init for Tegra186 SoCs
3 *
4 * Copyright (c) 2017 NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/* include hw specification */
20#include "host1x06.h"
21#include "host1x06_hardware.h"
22
23/* include code */
24#define HOST1X_HW 6
25
26#include "cdma_hw.c"
27#include "channel_hw.c"
28#include "debug_hw.c"
29#include "intr_hw.c"
30#include "syncpt_hw.c"
31
32#include "../dev.h"
33
34int host1x06_init(struct host1x *host)
35{
36 host->channel_op = &host1x_channel_ops;
37 host->cdma_op = &host1x_cdma_ops;
38 host->cdma_pb_op = &host1x_pushbuffer_ops;
39 host->syncpt_op = &host1x_syncpt_ops;
40 host->intr_op = &host1x_intr_ops;
41 host->debug_op = &host1x_debug_ops;
42
43 return 0;
44}
diff --git a/drivers/gpu/host1x/hw/host1x06.h b/drivers/gpu/host1x/hw/host1x06.h
new file mode 100644
index 000000000000..d9abe1489241
--- /dev/null
+++ b/drivers/gpu/host1x/hw/host1x06.h
@@ -0,0 +1,26 @@
1/*
2 * Host1x init for Tegra186 SoCs
3 *
4 * Copyright (c) 2017 NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef HOST1X_HOST1X06_H
20#define HOST1X_HOST1X06_H
21
22struct host1x;
23
24int host1x06_init(struct host1x *host);
25
26#endif
diff --git a/drivers/gpu/host1x/hw/host1x06_hardware.h b/drivers/gpu/host1x/hw/host1x06_hardware.h
new file mode 100644
index 000000000000..3039c92ea605
--- /dev/null
+++ b/drivers/gpu/host1x/hw/host1x06_hardware.h
@@ -0,0 +1,142 @@
1/*
2 * Tegra host1x Register Offsets for Tegra186
3 *
4 * Copyright (c) 2017 NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __HOST1X_HOST1X06_HARDWARE_H
20#define __HOST1X_HOST1X06_HARDWARE_H
21
22#include <linux/types.h>
23#include <linux/bitops.h>
24
25#include "hw_host1x06_uclass.h"
26#include "hw_host1x06_vm.h"
27#include "hw_host1x06_hypervisor.h"
28
29static inline u32 host1x_class_host_wait_syncpt(
30 unsigned indx, unsigned threshold)
31{
32 return host1x_uclass_wait_syncpt_indx_f(indx)
33 | host1x_uclass_wait_syncpt_thresh_f(threshold);
34}
35
36static inline u32 host1x_class_host_load_syncpt_base(
37 unsigned indx, unsigned threshold)
38{
39 return host1x_uclass_load_syncpt_base_base_indx_f(indx)
40 | host1x_uclass_load_syncpt_base_value_f(threshold);
41}
42
43static inline u32 host1x_class_host_wait_syncpt_base(
44 unsigned indx, unsigned base_indx, unsigned offset)
45{
46 return host1x_uclass_wait_syncpt_base_indx_f(indx)
47 | host1x_uclass_wait_syncpt_base_base_indx_f(base_indx)
48 | host1x_uclass_wait_syncpt_base_offset_f(offset);
49}
50
51static inline u32 host1x_class_host_incr_syncpt_base(
52 unsigned base_indx, unsigned offset)
53{
54 return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx)
55 | host1x_uclass_incr_syncpt_base_offset_f(offset);
56}
57
58static inline u32 host1x_class_host_incr_syncpt(
59 unsigned cond, unsigned indx)
60{
61 return host1x_uclass_incr_syncpt_cond_f(cond)
62 | host1x_uclass_incr_syncpt_indx_f(indx);
63}
64
65static inline u32 host1x_class_host_indoff_reg_write(
66 unsigned mod_id, unsigned offset, bool auto_inc)
67{
68 u32 v = host1x_uclass_indoff_indbe_f(0xf)
69 | host1x_uclass_indoff_indmodid_f(mod_id)
70 | host1x_uclass_indoff_indroffset_f(offset);
71 if (auto_inc)
72 v |= host1x_uclass_indoff_autoinc_f(1);
73 return v;
74}
75
76static inline u32 host1x_class_host_indoff_reg_read(
77 unsigned mod_id, unsigned offset, bool auto_inc)
78{
79 u32 v = host1x_uclass_indoff_indmodid_f(mod_id)
80 | host1x_uclass_indoff_indroffset_f(offset)
81 | host1x_uclass_indoff_rwn_read_v();
82 if (auto_inc)
83 v |= host1x_uclass_indoff_autoinc_f(1);
84 return v;
85}
86
87/* cdma opcodes */
88static inline u32 host1x_opcode_setclass(
89 unsigned class_id, unsigned offset, unsigned mask)
90{
91 return (0 << 28) | (offset << 16) | (class_id << 6) | mask;
92}
93
94static inline u32 host1x_opcode_incr(unsigned offset, unsigned count)
95{
96 return (1 << 28) | (offset << 16) | count;
97}
98
99static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count)
100{
101 return (2 << 28) | (offset << 16) | count;
102}
103
104static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask)
105{
106 return (3 << 28) | (offset << 16) | mask;
107}
108
109static inline u32 host1x_opcode_imm(unsigned offset, unsigned value)
110{
111 return (4 << 28) | (offset << 16) | value;
112}
113
114static inline u32 host1x_opcode_imm_incr_syncpt(unsigned cond, unsigned indx)
115{
116 return host1x_opcode_imm(host1x_uclass_incr_syncpt_r(),
117 host1x_class_host_incr_syncpt(cond, indx));
118}
119
120static inline u32 host1x_opcode_restart(unsigned address)
121{
122 return (5 << 28) | (address >> 4);
123}
124
125static inline u32 host1x_opcode_gather(unsigned count)
126{
127 return (6 << 28) | count;
128}
129
130static inline u32 host1x_opcode_gather_nonincr(unsigned offset, unsigned count)
131{
132 return (6 << 28) | (offset << 16) | BIT(15) | count;
133}
134
135static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count)
136{
137 return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
138}
139
140#define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0)
141
142#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x04_channel.h b/drivers/gpu/host1x/hw/hw_host1x04_channel.h
index 95e6f96142b9..2e8b635aa660 100644
--- a/drivers/gpu/host1x/hw/hw_host1x04_channel.h
+++ b/drivers/gpu/host1x/hw/hw_host1x04_channel.h
@@ -117,5 +117,17 @@ static inline u32 host1x_channel_dmactrl_dmainitget(void)
117} 117}
118#define HOST1X_CHANNEL_DMACTRL_DMAINITGET \ 118#define HOST1X_CHANNEL_DMACTRL_DMAINITGET \
119 host1x_channel_dmactrl_dmainitget() 119 host1x_channel_dmactrl_dmainitget()
120static inline u32 host1x_channel_channelctrl_r(void)
121{
122 return 0x98;
123}
124#define HOST1X_CHANNEL_CHANNELCTRL \
125 host1x_channel_channelctrl_r()
126static inline u32 host1x_channel_channelctrl_kernel_filter_gbuffer_f(u32 v)
127{
128 return (v & 0x1) << 2;
129}
130#define HOST1X_CHANNEL_CHANNELCTRL_KERNEL_FILTER_GBUFFER(v) \
131 host1x_channel_channelctrl_kernel_filter_gbuffer_f(v)
120 132
121#endif 133#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x05_channel.h b/drivers/gpu/host1x/hw/hw_host1x05_channel.h
index fce6e2c1ff4c..abbbc2641ce6 100644
--- a/drivers/gpu/host1x/hw/hw_host1x05_channel.h
+++ b/drivers/gpu/host1x/hw/hw_host1x05_channel.h
@@ -117,5 +117,17 @@ static inline u32 host1x_channel_dmactrl_dmainitget(void)
117} 117}
118#define HOST1X_CHANNEL_DMACTRL_DMAINITGET \ 118#define HOST1X_CHANNEL_DMACTRL_DMAINITGET \
119 host1x_channel_dmactrl_dmainitget() 119 host1x_channel_dmactrl_dmainitget()
120static inline u32 host1x_channel_channelctrl_r(void)
121{
122 return 0x98;
123}
124#define HOST1X_CHANNEL_CHANNELCTRL \
125 host1x_channel_channelctrl_r()
126static inline u32 host1x_channel_channelctrl_kernel_filter_gbuffer_f(u32 v)
127{
128 return (v & 0x1) << 2;
129}
130#define HOST1X_CHANNEL_CHANNELCTRL_KERNEL_FILTER_GBUFFER(v) \
131 host1x_channel_channelctrl_kernel_filter_gbuffer_f(v)
120 132
121#endif 133#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x06_hypervisor.h b/drivers/gpu/host1x/hw/hw_host1x06_hypervisor.h
new file mode 100644
index 000000000000..c05dab8a178b
--- /dev/null
+++ b/drivers/gpu/host1x/hw/hw_host1x06_hypervisor.h
@@ -0,0 +1,32 @@
1/*
2 * Copyright (c) 2017 NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#define HOST1X_HV_SYNCPT_PROT_EN 0x1ac4
19#define HOST1X_HV_SYNCPT_PROT_EN_CH_EN BIT(1)
20#define HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(x) (0x2020 + (x * 4))
21#define HOST1X_HV_CMDFIFO_PEEK_CTRL 0x233c
22#define HOST1X_HV_CMDFIFO_PEEK_CTRL_ADDR(x) (x)
23#define HOST1X_HV_CMDFIFO_PEEK_CTRL_CHANNEL(x) ((x) << 16)
24#define HOST1X_HV_CMDFIFO_PEEK_CTRL_ENABLE BIT(31)
25#define HOST1X_HV_CMDFIFO_PEEK_READ 0x2340
26#define HOST1X_HV_CMDFIFO_PEEK_PTRS 0x2344
27#define HOST1X_HV_CMDFIFO_PEEK_PTRS_WR_PTR_V(x) (((x) >> 16) & 0xfff)
28#define HOST1X_HV_CMDFIFO_PEEK_PTRS_RD_PTR_V(x) ((x) & 0xfff)
29#define HOST1X_HV_CMDFIFO_SETUP(x) (0x2588 + (x * 4))
30#define HOST1X_HV_CMDFIFO_SETUP_LIMIT_V(x) (((x) >> 16) & 0xfff)
31#define HOST1X_HV_CMDFIFO_SETUP_BASE_V(x) ((x) & 0xfff)
32#define HOST1X_HV_ICG_EN_OVERRIDE 0x2aa8
diff --git a/drivers/gpu/host1x/hw/hw_host1x06_uclass.h b/drivers/gpu/host1x/hw/hw_host1x06_uclass.h
new file mode 100644
index 000000000000..4457486c72b0
--- /dev/null
+++ b/drivers/gpu/host1x/hw/hw_host1x06_uclass.h
@@ -0,0 +1,181 @@
1/*
2 * Copyright (c) 2017 NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 /*
19 * Function naming determines intended use:
20 *
21 * <x>_r(void) : Returns the offset for register <x>.
22 *
23 * <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
24 *
25 * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
26 *
27 * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
28 * and masked to place it at field <y> of register <x>. This value
29 * can be |'d with others to produce a full register value for
30 * register <x>.
31 *
32 * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
33 * value can be ~'d and then &'d to clear the value of field <y> for
34 * register <x>.
35 *
36 * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
37 * to place it at field <y> of register <x>. This value can be |'d
38 * with others to produce a full register value for <x>.
39 *
40 * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
41 * <x> value 'r' after being shifted to place its LSB at bit 0.
42 * This value is suitable for direct comparison with other unshifted
43 * values appropriate for use in field <y> of register <x>.
44 *
45 * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
46 * field <y> of register <x>. This value is suitable for direct
47 * comparison with unshifted values appropriate for use in field <y>
48 * of register <x>.
49 */
50
51#ifndef HOST1X_HW_HOST1X06_UCLASS_H
52#define HOST1X_HW_HOST1X06_UCLASS_H
53
54static inline u32 host1x_uclass_incr_syncpt_r(void)
55{
56 return 0x0;
57}
58#define HOST1X_UCLASS_INCR_SYNCPT \
59 host1x_uclass_incr_syncpt_r()
60static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
61{
62 return (v & 0xff) << 8;
63}
64#define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \
65 host1x_uclass_incr_syncpt_cond_f(v)
66static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
67{
68 return (v & 0xff) << 0;
69}
70#define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \
71 host1x_uclass_incr_syncpt_indx_f(v)
72static inline u32 host1x_uclass_wait_syncpt_r(void)
73{
74 return 0x8;
75}
76#define HOST1X_UCLASS_WAIT_SYNCPT \
77 host1x_uclass_wait_syncpt_r()
78static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v)
79{
80 return (v & 0xff) << 24;
81}
82#define HOST1X_UCLASS_WAIT_SYNCPT_INDX_F(v) \
83 host1x_uclass_wait_syncpt_indx_f(v)
84static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v)
85{
86 return (v & 0xffffff) << 0;
87}
88#define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \
89 host1x_uclass_wait_syncpt_thresh_f(v)
90static inline u32 host1x_uclass_wait_syncpt_base_r(void)
91{
92 return 0x9;
93}
94#define HOST1X_UCLASS_WAIT_SYNCPT_BASE \
95 host1x_uclass_wait_syncpt_base_r()
96static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v)
97{
98 return (v & 0xff) << 24;
99}
100#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_INDX_F(v) \
101 host1x_uclass_wait_syncpt_base_indx_f(v)
102static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v)
103{
104 return (v & 0xff) << 16;
105}
106#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_BASE_INDX_F(v) \
107 host1x_uclass_wait_syncpt_base_base_indx_f(v)
108static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v)
109{
110 return (v & 0xffff) << 0;
111}
112#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \
113 host1x_uclass_wait_syncpt_base_offset_f(v)
114static inline u32 host1x_uclass_load_syncpt_base_r(void)
115{
116 return 0xb;
117}
118#define HOST1X_UCLASS_LOAD_SYNCPT_BASE \
119 host1x_uclass_load_syncpt_base_r()
120static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
121{
122 return (v & 0xff) << 24;
123}
124#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(v) \
125 host1x_uclass_load_syncpt_base_base_indx_f(v)
126static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v)
127{
128 return (v & 0xffffff) << 0;
129}
130#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(v) \
131 host1x_uclass_load_syncpt_base_value_f(v)
132static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v)
133{
134 return (v & 0xff) << 24;
135}
136#define HOST1X_UCLASS_INCR_SYNCPT_BASE_BASE_INDX_F(v) \
137 host1x_uclass_incr_syncpt_base_base_indx_f(v)
138static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v)
139{
140 return (v & 0xffffff) << 0;
141}
142#define HOST1X_UCLASS_INCR_SYNCPT_BASE_OFFSET_F(v) \
143 host1x_uclass_incr_syncpt_base_offset_f(v)
144static inline u32 host1x_uclass_indoff_r(void)
145{
146 return 0x2d;
147}
148#define HOST1X_UCLASS_INDOFF \
149 host1x_uclass_indoff_r()
150static inline u32 host1x_uclass_indoff_indbe_f(u32 v)
151{
152 return (v & 0xf) << 28;
153}
154#define HOST1X_UCLASS_INDOFF_INDBE_F(v) \
155 host1x_uclass_indoff_indbe_f(v)
156static inline u32 host1x_uclass_indoff_autoinc_f(u32 v)
157{
158 return (v & 0x1) << 27;
159}
160#define HOST1X_UCLASS_INDOFF_AUTOINC_F(v) \
161 host1x_uclass_indoff_autoinc_f(v)
162static inline u32 host1x_uclass_indoff_indmodid_f(u32 v)
163{
164 return (v & 0xff) << 18;
165}
166#define HOST1X_UCLASS_INDOFF_INDMODID_F(v) \
167 host1x_uclass_indoff_indmodid_f(v)
168static inline u32 host1x_uclass_indoff_indroffset_f(u32 v)
169{
170 return (v & 0xffff) << 2;
171}
172#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \
173 host1x_uclass_indoff_indroffset_f(v)
174static inline u32 host1x_uclass_indoff_rwn_read_v(void)
175{
176 return 1;
177}
178#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \
179 host1x_uclass_indoff_indroffset_f(v)
180
181#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x06_vm.h b/drivers/gpu/host1x/hw/hw_host1x06_vm.h
new file mode 100644
index 000000000000..e54b33902332
--- /dev/null
+++ b/drivers/gpu/host1x/hw/hw_host1x06_vm.h
@@ -0,0 +1,47 @@
1/*
2 * Copyright (c) 2017 NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#define HOST1X_CHANNEL_DMASTART 0x0000
19#define HOST1X_CHANNEL_DMASTART_HI 0x0004
20#define HOST1X_CHANNEL_DMAPUT 0x0008
21#define HOST1X_CHANNEL_DMAPUT_HI 0x000c
22#define HOST1X_CHANNEL_DMAGET 0x0010
23#define HOST1X_CHANNEL_DMAGET_HI 0x0014
24#define HOST1X_CHANNEL_DMAEND 0x0018
25#define HOST1X_CHANNEL_DMAEND_HI 0x001c
26#define HOST1X_CHANNEL_DMACTRL 0x0020
27#define HOST1X_CHANNEL_DMACTRL_DMASTOP BIT(0)
28#define HOST1X_CHANNEL_DMACTRL_DMAGETRST BIT(1)
29#define HOST1X_CHANNEL_DMACTRL_DMAINITGET BIT(2)
30#define HOST1X_CHANNEL_CMDFIFO_STAT 0x0024
31#define HOST1X_CHANNEL_CMDFIFO_STAT_EMPTY BIT(13)
32#define HOST1X_CHANNEL_CMDFIFO_RDATA 0x0028
33#define HOST1X_CHANNEL_CMDP_OFFSET 0x0030
34#define HOST1X_CHANNEL_CMDP_CLASS 0x0034
35#define HOST1X_CHANNEL_CHANNELSTAT 0x0038
36#define HOST1X_CHANNEL_CMDPROC_STOP 0x0048
37#define HOST1X_CHANNEL_TEARDOWN 0x004c
38
39#define HOST1X_SYNC_SYNCPT_CPU_INCR(x) (0x6400 + 4*(x))
40#define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(x) (0x6464 + 4*(x))
41#define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(x) (0x652c + 4*(x))
42#define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(x) (0x6590 + 4*(x))
43#define HOST1X_SYNC_SYNCPT_BASE(x) (0x8000 + 4*(x))
44#define HOST1X_SYNC_SYNCPT(x) (0x8080 + 4*(x))
45#define HOST1X_SYNC_SYNCPT_INT_THRESH(x) (0x8a00 + 4*(x))
46#define HOST1X_SYNC_SYNCPT_CH_APP(x) (0x9384 + 4*(x))
47#define HOST1X_SYNC_SYNCPT_CH_APP_CH(v) (((v) & 0x3f) << 8)
diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c
index 37ebb51703fa..329239237090 100644
--- a/drivers/gpu/host1x/hw/intr_hw.c
+++ b/drivers/gpu/host1x/hw/intr_hw.c
@@ -72,6 +72,23 @@ static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host)
72 } 72 }
73} 73}
74 74
75static void intr_hw_init(struct host1x *host, u32 cpm)
76{
77#if HOST1X_HW < 6
78 /* disable the ip_busy_timeout. this prevents write drops */
79 host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT);
80
81 /*
82 * increase the auto-ack timout to the maximum value. 2d will hang
83 * otherwise on Tegra2.
84 */
85 host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG);
86
87 /* update host clocks per usec */
88 host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK);
89#endif
90}
91
75static int 92static int
76_host1x_intr_init_host_sync(struct host1x *host, u32 cpm, 93_host1x_intr_init_host_sync(struct host1x *host, u32 cpm,
77 void (*syncpt_thresh_work)(struct work_struct *)) 94 void (*syncpt_thresh_work)(struct work_struct *))
@@ -92,17 +109,7 @@ _host1x_intr_init_host_sync(struct host1x *host, u32 cpm,
92 return err; 109 return err;
93 } 110 }
94 111
95 /* disable the ip_busy_timeout. this prevents write drops */ 112 intr_hw_init(host, cpm);
96 host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT);
97
98 /*
99 * increase the auto-ack timout to the maximum value. 2d will hang
100 * otherwise on Tegra2.
101 */
102 host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG);
103
104 /* update host clocks per usec */
105 host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK);
106 113
107 return 0; 114 return 0;
108} 115}
diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c
index 7b0270d60742..7dfd47d74f89 100644
--- a/drivers/gpu/host1x/hw/syncpt_hw.c
+++ b/drivers/gpu/host1x/hw/syncpt_hw.c
@@ -106,6 +106,50 @@ static int syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr)
106 return 0; 106 return 0;
107} 107}
108 108
109/**
110 * syncpt_assign_to_channel() - Assign syncpoint to channel
111 * @sp: syncpoint
112 * @ch: channel
113 *
114 * On chips with the syncpoint protection feature (Tegra186+), assign @sp to
115 * @ch, preventing other channels from incrementing the syncpoints. If @ch is
116 * NULL, unassigns the syncpoint.
117 *
118 * On older chips, do nothing.
119 */
120static void syncpt_assign_to_channel(struct host1x_syncpt *sp,
121 struct host1x_channel *ch)
122{
123#if HOST1X_HW >= 6
124 struct host1x *host = sp->host;
125
126 if (!host->hv_regs)
127 return;
128
129 host1x_sync_writel(host,
130 HOST1X_SYNC_SYNCPT_CH_APP_CH(ch ? ch->id : 0xff),
131 HOST1X_SYNC_SYNCPT_CH_APP(sp->id));
132#endif
133}
134
135/**
136 * syncpt_enable_protection() - Enable syncpoint protection
137 * @host: host1x instance
138 *
139 * On chips with the syncpoint protection feature (Tegra186+), enable this
140 * feature. On older chips, do nothing.
141 */
142static void syncpt_enable_protection(struct host1x *host)
143{
144#if HOST1X_HW >= 6
145 if (!host->hv_regs)
146 return;
147
148 host1x_hypervisor_writel(host, HOST1X_HV_SYNCPT_PROT_EN_CH_EN,
149 HOST1X_HV_SYNCPT_PROT_EN);
150#endif
151}
152
109static const struct host1x_syncpt_ops host1x_syncpt_ops = { 153static const struct host1x_syncpt_ops host1x_syncpt_ops = {
110 .restore = syncpt_restore, 154 .restore = syncpt_restore,
111 .restore_wait_base = syncpt_restore_wait_base, 155 .restore_wait_base = syncpt_restore_wait_base,
@@ -113,4 +157,6 @@ static const struct host1x_syncpt_ops host1x_syncpt_ops = {
113 .load = syncpt_load, 157 .load = syncpt_load,
114 .cpu_incr = syncpt_cpu_incr, 158 .cpu_incr = syncpt_cpu_incr,
115 .patch_wait = syncpt_patch_wait, 159 .patch_wait = syncpt_patch_wait,
160 .assign_to_channel = syncpt_assign_to_channel,
161 .enable_protection = syncpt_enable_protection,
116}; 162};
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c
index 048ac9e344ce..a2a952adc136 100644
--- a/drivers/gpu/host1x/syncpt.c
+++ b/drivers/gpu/host1x/syncpt.c
@@ -54,7 +54,7 @@ static void host1x_syncpt_base_free(struct host1x_syncpt_base *base)
54} 54}
55 55
56static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, 56static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
57 struct device *dev, 57 struct host1x_client *client,
58 unsigned long flags) 58 unsigned long flags)
59{ 59{
60 int i; 60 int i;
@@ -76,11 +76,11 @@ static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
76 } 76 }
77 77
78 name = kasprintf(GFP_KERNEL, "%02u-%s", sp->id, 78 name = kasprintf(GFP_KERNEL, "%02u-%s", sp->id,
79 dev ? dev_name(dev) : NULL); 79 client ? dev_name(client->dev) : NULL);
80 if (!name) 80 if (!name)
81 goto free_base; 81 goto free_base;
82 82
83 sp->dev = dev; 83 sp->client = client;
84 sp->name = name; 84 sp->name = name;
85 85
86 if (flags & HOST1X_SYNCPT_CLIENT_MANAGED) 86 if (flags & HOST1X_SYNCPT_CLIENT_MANAGED)
@@ -398,6 +398,13 @@ int host1x_syncpt_init(struct host1x *host)
398 for (i = 0; i < host->info->nb_pts; i++) { 398 for (i = 0; i < host->info->nb_pts; i++) {
399 syncpt[i].id = i; 399 syncpt[i].id = i;
400 syncpt[i].host = host; 400 syncpt[i].host = host;
401
402 /*
403 * Unassign syncpt from channels for purposes of Tegra186
404 * syncpoint protection. This prevents any channel from
405 * accessing it until it is reassigned.
406 */
407 host1x_hw_syncpt_assign_to_channel(host, &syncpt[i], NULL);
401 } 408 }
402 409
403 for (i = 0; i < host->info->nb_bases; i++) 410 for (i = 0; i < host->info->nb_bases; i++)
@@ -408,6 +415,7 @@ int host1x_syncpt_init(struct host1x *host)
408 host->bases = bases; 415 host->bases = bases;
409 416
410 host1x_syncpt_restore(host); 417 host1x_syncpt_restore(host);
418 host1x_hw_syncpt_enable_protection(host);
411 419
412 /* Allocate sync point to use for clearing waits for expired fences */ 420 /* Allocate sync point to use for clearing waits for expired fences */
413 host->nop_sp = host1x_syncpt_alloc(host, NULL, 0); 421 host->nop_sp = host1x_syncpt_alloc(host, NULL, 0);
@@ -419,7 +427,7 @@ int host1x_syncpt_init(struct host1x *host)
419 427
420/** 428/**
421 * host1x_syncpt_request() - request a syncpoint 429 * host1x_syncpt_request() - request a syncpoint
422 * @dev: device requesting the syncpoint 430 * @client: client requesting the syncpoint
423 * @flags: flags 431 * @flags: flags
424 * 432 *
425 * host1x client drivers can use this function to allocate a syncpoint for 433 * host1x client drivers can use this function to allocate a syncpoint for
@@ -427,12 +435,12 @@ int host1x_syncpt_init(struct host1x *host)
427 * use by the client exclusively. When no longer using a syncpoint, a host1x 435 * use by the client exclusively. When no longer using a syncpoint, a host1x
428 * client driver needs to release it using host1x_syncpt_free(). 436 * client driver needs to release it using host1x_syncpt_free().
429 */ 437 */
430struct host1x_syncpt *host1x_syncpt_request(struct device *dev, 438struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client,
431 unsigned long flags) 439 unsigned long flags)
432{ 440{
433 struct host1x *host = dev_get_drvdata(dev->parent); 441 struct host1x *host = dev_get_drvdata(client->parent->parent);
434 442
435 return host1x_syncpt_alloc(host, dev, flags); 443 return host1x_syncpt_alloc(host, client, flags);
436} 444}
437EXPORT_SYMBOL(host1x_syncpt_request); 445EXPORT_SYMBOL(host1x_syncpt_request);
438 446
@@ -456,7 +464,7 @@ void host1x_syncpt_free(struct host1x_syncpt *sp)
456 host1x_syncpt_base_free(sp->base); 464 host1x_syncpt_base_free(sp->base);
457 kfree(sp->name); 465 kfree(sp->name);
458 sp->base = NULL; 466 sp->base = NULL;
459 sp->dev = NULL; 467 sp->client = NULL;
460 sp->name = NULL; 468 sp->name = NULL;
461 sp->client_managed = false; 469 sp->client_managed = false;
462 470
diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h
index f719205105ac..9d88d37c2397 100644
--- a/drivers/gpu/host1x/syncpt.h
+++ b/drivers/gpu/host1x/syncpt.h
@@ -44,7 +44,7 @@ struct host1x_syncpt {
44 const char *name; 44 const char *name;
45 bool client_managed; 45 bool client_managed;
46 struct host1x *host; 46 struct host1x *host;
47 struct device *dev; 47 struct host1x_client *client;
48 struct host1x_syncpt_base *base; 48 struct host1x_syncpt_base *base;
49 49
50 /* interrupt data */ 50 /* interrupt data */
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index 630b1a98ab58..ddf7f9ca86cc 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -157,7 +157,7 @@ int host1x_syncpt_incr(struct host1x_syncpt *sp);
157u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs); 157u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
158int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, 158int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
159 u32 *value); 159 u32 *value);
160struct host1x_syncpt *host1x_syncpt_request(struct device *dev, 160struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client,
161 unsigned long flags); 161 unsigned long flags);
162void host1x_syncpt_free(struct host1x_syncpt *sp); 162void host1x_syncpt_free(struct host1x_syncpt *sp);
163 163