1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2013 Avionic Design GmbH
4 * Copyright (C) 2013 NVIDIA Corporation
8 #include <linux/host1x.h>
9 #include <linux/iommu.h>
10 #include <linux/module.h>
11 #include <linux/of_device.h>
12 #include <linux/platform_device.h>
13 #include <linux/reset.h>
15 #include <soc/tegra/pmc.h>
26 struct tegra_drm_client client
;
27 struct host1x_channel
*channel
;
28 struct clk
*clk_secondary
;
30 struct reset_control
*rst_secondary
;
31 struct reset_control
*rst
;
33 const struct gr3d_soc
*soc
;
35 DECLARE_BITMAP(addr_regs
, GR3D_NUM_REGS
);
38 static inline struct gr3d
*to_gr3d(struct tegra_drm_client
*client
)
40 return container_of(client
, struct gr3d
, client
);
43 static int gr3d_init(struct host1x_client
*client
)
45 struct tegra_drm_client
*drm
= host1x_to_drm_client(client
);
46 struct drm_device
*dev
= dev_get_drvdata(client
->host
);
47 unsigned long flags
= HOST1X_SYNCPT_HAS_BASE
;
48 struct gr3d
*gr3d
= to_gr3d(drm
);
51 gr3d
->channel
= host1x_channel_request(client
);
55 client
->syncpts
[0] = host1x_syncpt_request(client
, flags
);
56 if (!client
->syncpts
[0]) {
58 dev_err(client
->dev
, "failed to request syncpoint: %d\n", err
);
62 err
= host1x_client_iommu_attach(client
);
64 dev_err(client
->dev
, "failed to attach to domain: %d\n", err
);
68 err
= tegra_drm_register_client(dev
->dev_private
, drm
);
70 dev_err(client
->dev
, "failed to register client: %d\n", err
);
77 host1x_client_iommu_detach(client
);
79 host1x_syncpt_free(client
->syncpts
[0]);
81 host1x_channel_put(gr3d
->channel
);
85 static int gr3d_exit(struct host1x_client
*client
)
87 struct tegra_drm_client
*drm
= host1x_to_drm_client(client
);
88 struct drm_device
*dev
= dev_get_drvdata(client
->host
);
89 struct gr3d
*gr3d
= to_gr3d(drm
);
92 err
= tegra_drm_unregister_client(dev
->dev_private
, drm
);
96 host1x_client_iommu_detach(client
);
97 host1x_syncpt_free(client
->syncpts
[0]);
98 host1x_channel_put(gr3d
->channel
);
103 static const struct host1x_client_ops gr3d_client_ops
= {
108 static int gr3d_open_channel(struct tegra_drm_client
*client
,
109 struct tegra_drm_context
*context
)
111 struct gr3d
*gr3d
= to_gr3d(client
);
113 context
->channel
= host1x_channel_get(gr3d
->channel
);
114 if (!context
->channel
)
120 static void gr3d_close_channel(struct tegra_drm_context
*context
)
122 host1x_channel_put(context
->channel
);
125 static int gr3d_is_addr_reg(struct device
*dev
, u32
class, u32 offset
)
127 struct gr3d
*gr3d
= dev_get_drvdata(dev
);
130 case HOST1X_CLASS_HOST1X
:
136 case HOST1X_CLASS_GR3D
:
137 if (offset
>= GR3D_NUM_REGS
)
140 if (test_bit(offset
, gr3d
->addr_regs
))
149 static const struct tegra_drm_client_ops gr3d_ops
= {
150 .open_channel
= gr3d_open_channel
,
151 .close_channel
= gr3d_close_channel
,
152 .is_addr_reg
= gr3d_is_addr_reg
,
153 .submit
= tegra_drm_submit
,
156 static const struct gr3d_soc tegra20_gr3d_soc
= {
160 static const struct gr3d_soc tegra30_gr3d_soc
= {
164 static const struct gr3d_soc tegra114_gr3d_soc
= {
168 static const struct of_device_id tegra_gr3d_match
[] = {
169 { .compatible
= "nvidia,tegra114-gr3d", .data
= &tegra114_gr3d_soc
},
170 { .compatible
= "nvidia,tegra30-gr3d", .data
= &tegra30_gr3d_soc
},
171 { .compatible
= "nvidia,tegra20-gr3d", .data
= &tegra20_gr3d_soc
},
174 MODULE_DEVICE_TABLE(of
, tegra_gr3d_match
);
176 static const u32 gr3d_addr_regs
[] = {
177 GR3D_IDX_ATTRIBUTE( 0),
178 GR3D_IDX_ATTRIBUTE( 1),
179 GR3D_IDX_ATTRIBUTE( 2),
180 GR3D_IDX_ATTRIBUTE( 3),
181 GR3D_IDX_ATTRIBUTE( 4),
182 GR3D_IDX_ATTRIBUTE( 5),
183 GR3D_IDX_ATTRIBUTE( 6),
184 GR3D_IDX_ATTRIBUTE( 7),
185 GR3D_IDX_ATTRIBUTE( 8),
186 GR3D_IDX_ATTRIBUTE( 9),
187 GR3D_IDX_ATTRIBUTE(10),
188 GR3D_IDX_ATTRIBUTE(11),
189 GR3D_IDX_ATTRIBUTE(12),
190 GR3D_IDX_ATTRIBUTE(13),
191 GR3D_IDX_ATTRIBUTE(14),
192 GR3D_IDX_ATTRIBUTE(15),
197 GR3D_TEX_TEX_ADDR( 0),
198 GR3D_TEX_TEX_ADDR( 1),
199 GR3D_TEX_TEX_ADDR( 2),
200 GR3D_TEX_TEX_ADDR( 3),
201 GR3D_TEX_TEX_ADDR( 4),
202 GR3D_TEX_TEX_ADDR( 5),
203 GR3D_TEX_TEX_ADDR( 6),
204 GR3D_TEX_TEX_ADDR( 7),
205 GR3D_TEX_TEX_ADDR( 8),
206 GR3D_TEX_TEX_ADDR( 9),
207 GR3D_TEX_TEX_ADDR(10),
208 GR3D_TEX_TEX_ADDR(11),
209 GR3D_TEX_TEX_ADDR(12),
210 GR3D_TEX_TEX_ADDR(13),
211 GR3D_TEX_TEX_ADDR(14),
212 GR3D_TEX_TEX_ADDR(15),
213 GR3D_DW_MEMORY_OUTPUT_ADDRESS
,
214 GR3D_GLOBAL_SURFADDR( 0),
215 GR3D_GLOBAL_SURFADDR( 1),
216 GR3D_GLOBAL_SURFADDR( 2),
217 GR3D_GLOBAL_SURFADDR( 3),
218 GR3D_GLOBAL_SURFADDR( 4),
219 GR3D_GLOBAL_SURFADDR( 5),
220 GR3D_GLOBAL_SURFADDR( 6),
221 GR3D_GLOBAL_SURFADDR( 7),
222 GR3D_GLOBAL_SURFADDR( 8),
223 GR3D_GLOBAL_SURFADDR( 9),
224 GR3D_GLOBAL_SURFADDR(10),
225 GR3D_GLOBAL_SURFADDR(11),
226 GR3D_GLOBAL_SURFADDR(12),
227 GR3D_GLOBAL_SURFADDR(13),
228 GR3D_GLOBAL_SURFADDR(14),
229 GR3D_GLOBAL_SURFADDR(15),
230 GR3D_GLOBAL_SPILLSURFADDR
,
231 GR3D_GLOBAL_SURFOVERADDR( 0),
232 GR3D_GLOBAL_SURFOVERADDR( 1),
233 GR3D_GLOBAL_SURFOVERADDR( 2),
234 GR3D_GLOBAL_SURFOVERADDR( 3),
235 GR3D_GLOBAL_SURFOVERADDR( 4),
236 GR3D_GLOBAL_SURFOVERADDR( 5),
237 GR3D_GLOBAL_SURFOVERADDR( 6),
238 GR3D_GLOBAL_SURFOVERADDR( 7),
239 GR3D_GLOBAL_SURFOVERADDR( 8),
240 GR3D_GLOBAL_SURFOVERADDR( 9),
241 GR3D_GLOBAL_SURFOVERADDR(10),
242 GR3D_GLOBAL_SURFOVERADDR(11),
243 GR3D_GLOBAL_SURFOVERADDR(12),
244 GR3D_GLOBAL_SURFOVERADDR(13),
245 GR3D_GLOBAL_SURFOVERADDR(14),
246 GR3D_GLOBAL_SURFOVERADDR(15),
247 GR3D_GLOBAL_SAMP01SURFADDR( 0),
248 GR3D_GLOBAL_SAMP01SURFADDR( 1),
249 GR3D_GLOBAL_SAMP01SURFADDR( 2),
250 GR3D_GLOBAL_SAMP01SURFADDR( 3),
251 GR3D_GLOBAL_SAMP01SURFADDR( 4),
252 GR3D_GLOBAL_SAMP01SURFADDR( 5),
253 GR3D_GLOBAL_SAMP01SURFADDR( 6),
254 GR3D_GLOBAL_SAMP01SURFADDR( 7),
255 GR3D_GLOBAL_SAMP01SURFADDR( 8),
256 GR3D_GLOBAL_SAMP01SURFADDR( 9),
257 GR3D_GLOBAL_SAMP01SURFADDR(10),
258 GR3D_GLOBAL_SAMP01SURFADDR(11),
259 GR3D_GLOBAL_SAMP01SURFADDR(12),
260 GR3D_GLOBAL_SAMP01SURFADDR(13),
261 GR3D_GLOBAL_SAMP01SURFADDR(14),
262 GR3D_GLOBAL_SAMP01SURFADDR(15),
263 GR3D_GLOBAL_SAMP23SURFADDR( 0),
264 GR3D_GLOBAL_SAMP23SURFADDR( 1),
265 GR3D_GLOBAL_SAMP23SURFADDR( 2),
266 GR3D_GLOBAL_SAMP23SURFADDR( 3),
267 GR3D_GLOBAL_SAMP23SURFADDR( 4),
268 GR3D_GLOBAL_SAMP23SURFADDR( 5),
269 GR3D_GLOBAL_SAMP23SURFADDR( 6),
270 GR3D_GLOBAL_SAMP23SURFADDR( 7),
271 GR3D_GLOBAL_SAMP23SURFADDR( 8),
272 GR3D_GLOBAL_SAMP23SURFADDR( 9),
273 GR3D_GLOBAL_SAMP23SURFADDR(10),
274 GR3D_GLOBAL_SAMP23SURFADDR(11),
275 GR3D_GLOBAL_SAMP23SURFADDR(12),
276 GR3D_GLOBAL_SAMP23SURFADDR(13),
277 GR3D_GLOBAL_SAMP23SURFADDR(14),
278 GR3D_GLOBAL_SAMP23SURFADDR(15),
281 static int gr3d_probe(struct platform_device
*pdev
)
283 struct device_node
*np
= pdev
->dev
.of_node
;
284 struct host1x_syncpt
**syncpts
;
289 gr3d
= devm_kzalloc(&pdev
->dev
, sizeof(*gr3d
), GFP_KERNEL
);
293 gr3d
->soc
= of_device_get_match_data(&pdev
->dev
);
295 syncpts
= devm_kzalloc(&pdev
->dev
, sizeof(*syncpts
), GFP_KERNEL
);
299 gr3d
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
300 if (IS_ERR(gr3d
->clk
)) {
301 dev_err(&pdev
->dev
, "cannot get clock\n");
302 return PTR_ERR(gr3d
->clk
);
305 gr3d
->rst
= devm_reset_control_get(&pdev
->dev
, "3d");
306 if (IS_ERR(gr3d
->rst
)) {
307 dev_err(&pdev
->dev
, "cannot get reset\n");
308 return PTR_ERR(gr3d
->rst
);
311 if (of_device_is_compatible(np
, "nvidia,tegra30-gr3d")) {
312 gr3d
->clk_secondary
= devm_clk_get(&pdev
->dev
, "3d2");
313 if (IS_ERR(gr3d
->clk_secondary
)) {
314 dev_err(&pdev
->dev
, "cannot get secondary clock\n");
315 return PTR_ERR(gr3d
->clk_secondary
);
318 gr3d
->rst_secondary
= devm_reset_control_get(&pdev
->dev
,
320 if (IS_ERR(gr3d
->rst_secondary
)) {
321 dev_err(&pdev
->dev
, "cannot get secondary reset\n");
322 return PTR_ERR(gr3d
->rst_secondary
);
326 err
= tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D
, gr3d
->clk
,
329 dev_err(&pdev
->dev
, "failed to power up 3D unit\n");
333 if (gr3d
->clk_secondary
) {
334 err
= tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1
,
336 gr3d
->rst_secondary
);
339 "failed to power up secondary 3D unit\n");
344 INIT_LIST_HEAD(&gr3d
->client
.base
.list
);
345 gr3d
->client
.base
.ops
= &gr3d_client_ops
;
346 gr3d
->client
.base
.dev
= &pdev
->dev
;
347 gr3d
->client
.base
.class = HOST1X_CLASS_GR3D
;
348 gr3d
->client
.base
.syncpts
= syncpts
;
349 gr3d
->client
.base
.num_syncpts
= 1;
351 INIT_LIST_HEAD(&gr3d
->client
.list
);
352 gr3d
->client
.version
= gr3d
->soc
->version
;
353 gr3d
->client
.ops
= &gr3d_ops
;
355 err
= host1x_client_register(&gr3d
->client
.base
);
357 dev_err(&pdev
->dev
, "failed to register host1x client: %d\n",
362 /* initialize address register map */
363 for (i
= 0; i
< ARRAY_SIZE(gr3d_addr_regs
); i
++)
364 set_bit(gr3d_addr_regs
[i
], gr3d
->addr_regs
);
366 platform_set_drvdata(pdev
, gr3d
);
371 static int gr3d_remove(struct platform_device
*pdev
)
373 struct gr3d
*gr3d
= platform_get_drvdata(pdev
);
376 err
= host1x_client_unregister(&gr3d
->client
.base
);
378 dev_err(&pdev
->dev
, "failed to unregister host1x client: %d\n",
383 if (gr3d
->clk_secondary
) {
384 reset_control_assert(gr3d
->rst_secondary
);
385 tegra_powergate_power_off(TEGRA_POWERGATE_3D1
);
386 clk_disable_unprepare(gr3d
->clk_secondary
);
389 reset_control_assert(gr3d
->rst
);
390 tegra_powergate_power_off(TEGRA_POWERGATE_3D
);
391 clk_disable_unprepare(gr3d
->clk
);
396 struct platform_driver tegra_gr3d_driver
= {
398 .name
= "tegra-gr3d",
399 .of_match_table
= tegra_gr3d_match
,
402 .remove
= gr3d_remove
,