diff options
author | Eric Anholt <eric@anholt.net> | 2015-03-02 16:01:12 -0500 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2015-12-07 23:05:10 -0500 |
commit | d3f5168a0810005920e7a3d5ba83e249bd9a750c (patch) | |
tree | 82ef1d0cbb0a7e6b1aacb96c2dc8c835fabe4808 | |
parent | 1fa81589bbac16af6baf153ccc9b3f38fb16a498 (diff) |
drm/vc4: Bind and initialize the V3D engine.
This is the component of the GPU that does 3D rendering.
Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r-- | drivers/gpu/drm/vc4/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_debugfs.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_drv.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_drv.h | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_v3d.c | 225 |
5 files changed, 242 insertions, 0 deletions
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile index eb776a6a9899..e87a6f2f5916 100644 --- a/drivers/gpu/drm/vc4/Makefile +++ b/drivers/gpu/drm/vc4/Makefile | |||
@@ -11,6 +11,7 @@ vc4-y := \ | |||
11 | vc4_hdmi.o \ | 11 | vc4_hdmi.o \ |
12 | vc4_hvs.o \ | 12 | vc4_hvs.o \ |
13 | vc4_plane.o \ | 13 | vc4_plane.o \ |
14 | vc4_v3d.o \ | ||
14 | vc4_validate_shaders.o | 15 | vc4_validate_shaders.o |
15 | 16 | ||
16 | vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o | 17 | vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o |
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c index 6bcf96e9a482..d76ad10b07fd 100644 --- a/drivers/gpu/drm/vc4/vc4_debugfs.c +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c | |||
@@ -22,6 +22,8 @@ static const struct drm_info_list vc4_debugfs_list[] = { | |||
22 | {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0}, | 22 | {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0}, |
23 | {"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1}, | 23 | {"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1}, |
24 | {"crtc2_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)2}, | 24 | {"crtc2_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)2}, |
25 | {"v3d_ident", vc4_v3d_debugfs_ident, 0}, | ||
26 | {"v3d_regs", vc4_v3d_debugfs_regs, 0}, | ||
25 | }; | 27 | }; |
26 | 28 | ||
27 | #define VC4_DEBUGFS_ENTRIES ARRAY_SIZE(vc4_debugfs_list) | 29 | #define VC4_DEBUGFS_ENTRIES ARRAY_SIZE(vc4_debugfs_list) |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index da4be9c8f70d..db58d74efe95 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c | |||
@@ -236,6 +236,7 @@ static struct platform_driver *const component_drivers[] = { | |||
236 | &vc4_hdmi_driver, | 236 | &vc4_hdmi_driver, |
237 | &vc4_crtc_driver, | 237 | &vc4_crtc_driver, |
238 | &vc4_hvs_driver, | 238 | &vc4_hvs_driver, |
239 | &vc4_v3d_driver, | ||
239 | }; | 240 | }; |
240 | 241 | ||
241 | static int vc4_platform_drm_probe(struct platform_device *pdev) | 242 | static int vc4_platform_drm_probe(struct platform_device *pdev) |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index bd77d5574e30..8945463e70b6 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h | |||
@@ -15,6 +15,7 @@ struct vc4_dev { | |||
15 | struct vc4_hdmi *hdmi; | 15 | struct vc4_hdmi *hdmi; |
16 | struct vc4_hvs *hvs; | 16 | struct vc4_hvs *hvs; |
17 | struct vc4_crtc *crtc[3]; | 17 | struct vc4_crtc *crtc[3]; |
18 | struct vc4_v3d *v3d; | ||
18 | 19 | ||
19 | struct drm_fbdev_cma *fbdev; | 20 | struct drm_fbdev_cma *fbdev; |
20 | 21 | ||
@@ -82,6 +83,11 @@ to_vc4_bo(struct drm_gem_object *bo) | |||
82 | return (struct vc4_bo *)bo; | 83 | return (struct vc4_bo *)bo; |
83 | } | 84 | } |
84 | 85 | ||
86 | struct vc4_v3d { | ||
87 | struct platform_device *pdev; | ||
88 | void __iomem *regs; | ||
89 | }; | ||
90 | |||
85 | struct vc4_hvs { | 91 | struct vc4_hvs { |
86 | struct platform_device *pdev; | 92 | struct platform_device *pdev; |
87 | void __iomem *regs; | 93 | void __iomem *regs; |
@@ -119,6 +125,8 @@ to_vc4_encoder(struct drm_encoder *encoder) | |||
119 | return container_of(encoder, struct vc4_encoder, base); | 125 | return container_of(encoder, struct vc4_encoder, base); |
120 | } | 126 | } |
121 | 127 | ||
128 | #define V3D_READ(offset) readl(vc4->v3d->regs + offset) | ||
129 | #define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset) | ||
122 | #define HVS_READ(offset) readl(vc4->hvs->regs + offset) | 130 | #define HVS_READ(offset) readl(vc4->hvs->regs + offset) |
123 | #define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset) | 131 | #define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset) |
124 | 132 | ||
@@ -241,6 +249,11 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, | |||
241 | u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); | 249 | u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); |
242 | u32 vc4_plane_dlist_size(struct drm_plane_state *state); | 250 | u32 vc4_plane_dlist_size(struct drm_plane_state *state); |
243 | 251 | ||
252 | /* vc4_v3d.c */ | ||
253 | extern struct platform_driver vc4_v3d_driver; | ||
254 | int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); | ||
255 | int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused); | ||
256 | |||
244 | /* vc4_validate_shader.c */ | 257 | /* vc4_validate_shader.c */ |
245 | struct vc4_validated_shader_info * | 258 | struct vc4_validated_shader_info * |
246 | vc4_validate_shader(struct drm_gem_cma_object *shader_obj); | 259 | vc4_validate_shader(struct drm_gem_cma_object *shader_obj); |
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c new file mode 100644 index 000000000000..040ad0d8b8a1 --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_v3d.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 The Linux Foundation. All rights reserved. | ||
3 | * Copyright (C) 2013 Red Hat | ||
4 | * Author: Rob Clark <robdclark@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that 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 along with | ||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include "linux/component.h" | ||
20 | #include "vc4_drv.h" | ||
21 | #include "vc4_regs.h" | ||
22 | |||
23 | #ifdef CONFIG_DEBUG_FS | ||
24 | #define REGDEF(reg) { reg, #reg } | ||
25 | static const struct { | ||
26 | uint32_t reg; | ||
27 | const char *name; | ||
28 | } vc4_reg_defs[] = { | ||
29 | REGDEF(V3D_IDENT0), | ||
30 | REGDEF(V3D_IDENT1), | ||
31 | REGDEF(V3D_IDENT2), | ||
32 | REGDEF(V3D_SCRATCH), | ||
33 | REGDEF(V3D_L2CACTL), | ||
34 | REGDEF(V3D_SLCACTL), | ||
35 | REGDEF(V3D_INTCTL), | ||
36 | REGDEF(V3D_INTENA), | ||
37 | REGDEF(V3D_INTDIS), | ||
38 | REGDEF(V3D_CT0CS), | ||
39 | REGDEF(V3D_CT1CS), | ||
40 | REGDEF(V3D_CT0EA), | ||
41 | REGDEF(V3D_CT1EA), | ||
42 | REGDEF(V3D_CT0CA), | ||
43 | REGDEF(V3D_CT1CA), | ||
44 | REGDEF(V3D_CT00RA0), | ||
45 | REGDEF(V3D_CT01RA0), | ||
46 | REGDEF(V3D_CT0LC), | ||
47 | REGDEF(V3D_CT1LC), | ||
48 | REGDEF(V3D_CT0PC), | ||
49 | REGDEF(V3D_CT1PC), | ||
50 | REGDEF(V3D_PCS), | ||
51 | REGDEF(V3D_BFC), | ||
52 | REGDEF(V3D_RFC), | ||
53 | REGDEF(V3D_BPCA), | ||
54 | REGDEF(V3D_BPCS), | ||
55 | REGDEF(V3D_BPOA), | ||
56 | REGDEF(V3D_BPOS), | ||
57 | REGDEF(V3D_BXCF), | ||
58 | REGDEF(V3D_SQRSV0), | ||
59 | REGDEF(V3D_SQRSV1), | ||
60 | REGDEF(V3D_SQCNTL), | ||
61 | REGDEF(V3D_SRQPC), | ||
62 | REGDEF(V3D_SRQUA), | ||
63 | REGDEF(V3D_SRQUL), | ||
64 | REGDEF(V3D_SRQCS), | ||
65 | REGDEF(V3D_VPACNTL), | ||
66 | REGDEF(V3D_VPMBASE), | ||
67 | REGDEF(V3D_PCTRC), | ||
68 | REGDEF(V3D_PCTRE), | ||
69 | REGDEF(V3D_PCTR0), | ||
70 | REGDEF(V3D_PCTRS0), | ||
71 | REGDEF(V3D_PCTR1), | ||
72 | REGDEF(V3D_PCTRS1), | ||
73 | REGDEF(V3D_PCTR2), | ||
74 | REGDEF(V3D_PCTRS2), | ||
75 | REGDEF(V3D_PCTR3), | ||
76 | REGDEF(V3D_PCTRS3), | ||
77 | REGDEF(V3D_PCTR4), | ||
78 | REGDEF(V3D_PCTRS4), | ||
79 | REGDEF(V3D_PCTR5), | ||
80 | REGDEF(V3D_PCTRS5), | ||
81 | REGDEF(V3D_PCTR6), | ||
82 | REGDEF(V3D_PCTRS6), | ||
83 | REGDEF(V3D_PCTR7), | ||
84 | REGDEF(V3D_PCTRS7), | ||
85 | REGDEF(V3D_PCTR8), | ||
86 | REGDEF(V3D_PCTRS8), | ||
87 | REGDEF(V3D_PCTR9), | ||
88 | REGDEF(V3D_PCTRS9), | ||
89 | REGDEF(V3D_PCTR10), | ||
90 | REGDEF(V3D_PCTRS10), | ||
91 | REGDEF(V3D_PCTR11), | ||
92 | REGDEF(V3D_PCTRS11), | ||
93 | REGDEF(V3D_PCTR12), | ||
94 | REGDEF(V3D_PCTRS12), | ||
95 | REGDEF(V3D_PCTR13), | ||
96 | REGDEF(V3D_PCTRS13), | ||
97 | REGDEF(V3D_PCTR14), | ||
98 | REGDEF(V3D_PCTRS14), | ||
99 | REGDEF(V3D_PCTR15), | ||
100 | REGDEF(V3D_PCTRS15), | ||
101 | REGDEF(V3D_DBGE), | ||
102 | REGDEF(V3D_FDBGO), | ||
103 | REGDEF(V3D_FDBGB), | ||
104 | REGDEF(V3D_FDBGR), | ||
105 | REGDEF(V3D_FDBGS), | ||
106 | REGDEF(V3D_ERRSTAT), | ||
107 | }; | ||
108 | |||
109 | int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused) | ||
110 | { | ||
111 | struct drm_info_node *node = (struct drm_info_node *)m->private; | ||
112 | struct drm_device *dev = node->minor->dev; | ||
113 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
114 | int i; | ||
115 | |||
116 | for (i = 0; i < ARRAY_SIZE(vc4_reg_defs); i++) { | ||
117 | seq_printf(m, "%s (0x%04x): 0x%08x\n", | ||
118 | vc4_reg_defs[i].name, vc4_reg_defs[i].reg, | ||
119 | V3D_READ(vc4_reg_defs[i].reg)); | ||
120 | } | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused) | ||
126 | { | ||
127 | struct drm_info_node *node = (struct drm_info_node *)m->private; | ||
128 | struct drm_device *dev = node->minor->dev; | ||
129 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
130 | uint32_t ident1 = V3D_READ(V3D_IDENT1); | ||
131 | uint32_t nslc = VC4_GET_FIELD(ident1, V3D_IDENT1_NSLC); | ||
132 | uint32_t tups = VC4_GET_FIELD(ident1, V3D_IDENT1_TUPS); | ||
133 | uint32_t qups = VC4_GET_FIELD(ident1, V3D_IDENT1_QUPS); | ||
134 | |||
135 | seq_printf(m, "Revision: %d\n", | ||
136 | VC4_GET_FIELD(ident1, V3D_IDENT1_REV)); | ||
137 | seq_printf(m, "Slices: %d\n", nslc); | ||
138 | seq_printf(m, "TMUs: %d\n", nslc * tups); | ||
139 | seq_printf(m, "QPUs: %d\n", nslc * qups); | ||
140 | seq_printf(m, "Semaphores: %d\n", | ||
141 | VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM)); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | #endif /* CONFIG_DEBUG_FS */ | ||
146 | |||
147 | static void vc4_v3d_init_hw(struct drm_device *dev) | ||
148 | { | ||
149 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
150 | |||
151 | /* Take all the memory that would have been reserved for user | ||
152 | * QPU programs, since we don't have an interface for running | ||
153 | * them, anyway. | ||
154 | */ | ||
155 | V3D_WRITE(V3D_VPMBASE, 0); | ||
156 | } | ||
157 | |||
158 | static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) | ||
159 | { | ||
160 | struct platform_device *pdev = to_platform_device(dev); | ||
161 | struct drm_device *drm = dev_get_drvdata(master); | ||
162 | struct vc4_dev *vc4 = to_vc4_dev(drm); | ||
163 | struct vc4_v3d *v3d = NULL; | ||
164 | |||
165 | v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL); | ||
166 | if (!v3d) | ||
167 | return -ENOMEM; | ||
168 | |||
169 | v3d->pdev = pdev; | ||
170 | |||
171 | v3d->regs = vc4_ioremap_regs(pdev, 0); | ||
172 | if (IS_ERR(v3d->regs)) | ||
173 | return PTR_ERR(v3d->regs); | ||
174 | |||
175 | vc4->v3d = v3d; | ||
176 | |||
177 | if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) { | ||
178 | DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n", | ||
179 | V3D_READ(V3D_IDENT0), V3D_EXPECTED_IDENT0); | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | vc4_v3d_init_hw(drm); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static void vc4_v3d_unbind(struct device *dev, struct device *master, | ||
189 | void *data) | ||
190 | { | ||
191 | struct drm_device *drm = dev_get_drvdata(master); | ||
192 | struct vc4_dev *vc4 = to_vc4_dev(drm); | ||
193 | |||
194 | vc4->v3d = NULL; | ||
195 | } | ||
196 | |||
197 | static const struct component_ops vc4_v3d_ops = { | ||
198 | .bind = vc4_v3d_bind, | ||
199 | .unbind = vc4_v3d_unbind, | ||
200 | }; | ||
201 | |||
202 | static int vc4_v3d_dev_probe(struct platform_device *pdev) | ||
203 | { | ||
204 | return component_add(&pdev->dev, &vc4_v3d_ops); | ||
205 | } | ||
206 | |||
207 | static int vc4_v3d_dev_remove(struct platform_device *pdev) | ||
208 | { | ||
209 | component_del(&pdev->dev, &vc4_v3d_ops); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static const struct of_device_id vc4_v3d_dt_match[] = { | ||
214 | { .compatible = "brcm,vc4-v3d" }, | ||
215 | {} | ||
216 | }; | ||
217 | |||
218 | struct platform_driver vc4_v3d_driver = { | ||
219 | .probe = vc4_v3d_dev_probe, | ||
220 | .remove = vc4_v3d_dev_remove, | ||
221 | .driver = { | ||
222 | .name = "vc4_v3d", | ||
223 | .of_match_table = vc4_v3d_dt_match, | ||
224 | }, | ||
225 | }; | ||