2 * Copyright (C) 2013 Avionic Design GmbH
3 * Copyright (C) 2013 NVIDIA Corporation
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
10 #include <linux/clk.h>
11 #include <linux/host1x.h>
12 #include <linux/iommu.h>
13 #include <linux/module.h>
14 #include <linux/of_device.h>
15 #include <linux/platform_device.h>
16 #include <linux/reset.h>
18 #include <soc/tegra/pmc.h>
29 struct iommu_group
*group
;
30 struct tegra_drm_client client
;
31 struct host1x_channel
*channel
;
32 struct clk
*clk_secondary
;
34 struct reset_control
*rst_secondary
;
35 struct reset_control
*rst
;
37 const struct gr3d_soc
*soc
;
39 DECLARE_BITMAP(addr_regs
, GR3D_NUM_REGS
);
42 static inline struct gr3d
*to_gr3d(struct tegra_drm_client
*client
)
44 return container_of(client
, struct gr3d
, client
);
47 static int gr3d_init(struct host1x_client
*client
)
49 struct tegra_drm_client
*drm
= host1x_to_drm_client(client
);
50 struct drm_device
*dev
= dev_get_drvdata(client
->parent
);
51 unsigned long flags
= HOST1X_SYNCPT_HAS_BASE
;
52 struct gr3d
*gr3d
= to_gr3d(drm
);
55 gr3d
->channel
= host1x_channel_request(client
->dev
);
59 client
->syncpts
[0] = host1x_syncpt_request(client
, flags
);
60 if (!client
->syncpts
[0]) {
62 dev_err(client
->dev
, "failed to request syncpoint: %d\n", err
);
66 gr3d
->group
= host1x_client_iommu_attach(client
, false);
67 if (IS_ERR(gr3d
->group
)) {
68 err
= PTR_ERR(gr3d
->group
);
69 dev_err(client
->dev
, "failed to attach to domain: %d\n", err
);
73 err
= tegra_drm_register_client(dev
->dev_private
, drm
);
75 dev_err(client
->dev
, "failed to register client: %d\n", err
);
82 host1x_client_iommu_detach(client
, gr3d
->group
);
84 host1x_syncpt_free(client
->syncpts
[0]);
86 host1x_channel_put(gr3d
->channel
);
90 static int gr3d_exit(struct host1x_client
*client
)
92 struct tegra_drm_client
*drm
= host1x_to_drm_client(client
);
93 struct drm_device
*dev
= dev_get_drvdata(client
->parent
);
94 struct gr3d
*gr3d
= to_gr3d(drm
);
97 err
= tegra_drm_unregister_client(dev
->dev_private
, drm
);
101 host1x_client_iommu_detach(client
, gr3d
->group
);
102 host1x_syncpt_free(client
->syncpts
[0]);
103 host1x_channel_put(gr3d
->channel
);
108 static const struct host1x_client_ops gr3d_client_ops
= {
113 static int gr3d_open_channel(struct tegra_drm_client
*client
,
114 struct tegra_drm_context
*context
)
116 struct gr3d
*gr3d
= to_gr3d(client
);
118 context
->channel
= host1x_channel_get(gr3d
->channel
);
119 if (!context
->channel
)
125 static void gr3d_close_channel(struct tegra_drm_context
*context
)
127 host1x_channel_put(context
->channel
);
130 static int gr3d_is_addr_reg(struct device
*dev
, u32
class, u32 offset
)
132 struct gr3d
*gr3d
= dev_get_drvdata(dev
);
135 case HOST1X_CLASS_HOST1X
:
141 case HOST1X_CLASS_GR3D
:
142 if (offset
>= GR3D_NUM_REGS
)
145 if (test_bit(offset
, gr3d
->addr_regs
))
154 static const struct tegra_drm_client_ops gr3d_ops
= {
155 .open_channel
= gr3d_open_channel
,
156 .close_channel
= gr3d_close_channel
,
157 .is_addr_reg
= gr3d_is_addr_reg
,
158 .submit
= tegra_drm_submit
,
161 static const struct gr3d_soc tegra20_gr3d_soc
= {
165 static const struct gr3d_soc tegra30_gr3d_soc
= {
169 static const struct gr3d_soc tegra114_gr3d_soc
= {
173 static const struct of_device_id tegra_gr3d_match
[] = {
174 { .compatible
= "nvidia,tegra114-gr3d", .data
= &tegra114_gr3d_soc
},
175 { .compatible
= "nvidia,tegra30-gr3d", .data
= &tegra30_gr3d_soc
},
176 { .compatible
= "nvidia,tegra20-gr3d", .data
= &tegra20_gr3d_soc
},
179 MODULE_DEVICE_TABLE(of
, tegra_gr3d_match
);
181 static const u32 gr3d_addr_regs
[] = {
182 GR3D_IDX_ATTRIBUTE( 0),
183 GR3D_IDX_ATTRIBUTE( 1),
184 GR3D_IDX_ATTRIBUTE( 2),
185 GR3D_IDX_ATTRIBUTE( 3),
186 GR3D_IDX_ATTRIBUTE( 4),
187 GR3D_IDX_ATTRIBUTE( 5),
188 GR3D_IDX_ATTRIBUTE( 6),
189 GR3D_IDX_ATTRIBUTE( 7),
190 GR3D_IDX_ATTRIBUTE( 8),
191 GR3D_IDX_ATTRIBUTE( 9),
192 GR3D_IDX_ATTRIBUTE(10),
193 GR3D_IDX_ATTRIBUTE(11),
194 GR3D_IDX_ATTRIBUTE(12),
195 GR3D_IDX_ATTRIBUTE(13),
196 GR3D_IDX_ATTRIBUTE(14),
197 GR3D_IDX_ATTRIBUTE(15),
202 GR3D_TEX_TEX_ADDR( 0),
203 GR3D_TEX_TEX_ADDR( 1),
204 GR3D_TEX_TEX_ADDR( 2),
205 GR3D_TEX_TEX_ADDR( 3),
206 GR3D_TEX_TEX_ADDR( 4),
207 GR3D_TEX_TEX_ADDR( 5),
208 GR3D_TEX_TEX_ADDR( 6),
209 GR3D_TEX_TEX_ADDR( 7),
210 GR3D_TEX_TEX_ADDR( 8),
211 GR3D_TEX_TEX_ADDR( 9),
212 GR3D_TEX_TEX_ADDR(10),
213 GR3D_TEX_TEX_ADDR(11),
214 GR3D_TEX_TEX_ADDR(12),
215 GR3D_TEX_TEX_ADDR(13),
216 GR3D_TEX_TEX_ADDR(14),
217 GR3D_TEX_TEX_ADDR(15),
218 GR3D_DW_MEMORY_OUTPUT_ADDRESS
,
219 GR3D_GLOBAL_SURFADDR( 0),
220 GR3D_GLOBAL_SURFADDR( 1),
221 GR3D_GLOBAL_SURFADDR( 2),
222 GR3D_GLOBAL_SURFADDR( 3),
223 GR3D_GLOBAL_SURFADDR( 4),
224 GR3D_GLOBAL_SURFADDR( 5),
225 GR3D_GLOBAL_SURFADDR( 6),
226 GR3D_GLOBAL_SURFADDR( 7),
227 GR3D_GLOBAL_SURFADDR( 8),
228 GR3D_GLOBAL_SURFADDR( 9),
229 GR3D_GLOBAL_SURFADDR(10),
230 GR3D_GLOBAL_SURFADDR(11),
231 GR3D_GLOBAL_SURFADDR(12),
232 GR3D_GLOBAL_SURFADDR(13),
233 GR3D_GLOBAL_SURFADDR(14),
234 GR3D_GLOBAL_SURFADDR(15),
235 GR3D_GLOBAL_SPILLSURFADDR
,
236 GR3D_GLOBAL_SURFOVERADDR( 0),
237 GR3D_GLOBAL_SURFOVERADDR( 1),
238 GR3D_GLOBAL_SURFOVERADDR( 2),
239 GR3D_GLOBAL_SURFOVERADDR( 3),
240 GR3D_GLOBAL_SURFOVERADDR( 4),
241 GR3D_GLOBAL_SURFOVERADDR( 5),
242 GR3D_GLOBAL_SURFOVERADDR( 6),
243 GR3D_GLOBAL_SURFOVERADDR( 7),
244 GR3D_GLOBAL_SURFOVERADDR( 8),
245 GR3D_GLOBAL_SURFOVERADDR( 9),
246 GR3D_GLOBAL_SURFOVERADDR(10),
247 GR3D_GLOBAL_SURFOVERADDR(11),
248 GR3D_GLOBAL_SURFOVERADDR(12),
249 GR3D_GLOBAL_SURFOVERADDR(13),
250 GR3D_GLOBAL_SURFOVERADDR(14),
251 GR3D_GLOBAL_SURFOVERADDR(15),
252 GR3D_GLOBAL_SAMP01SURFADDR( 0),
253 GR3D_GLOBAL_SAMP01SURFADDR( 1),
254 GR3D_GLOBAL_SAMP01SURFADDR( 2),
255 GR3D_GLOBAL_SAMP01SURFADDR( 3),
256 GR3D_GLOBAL_SAMP01SURFADDR( 4),
257 GR3D_GLOBAL_SAMP01SURFADDR( 5),
258 GR3D_GLOBAL_SAMP01SURFADDR( 6),
259 GR3D_GLOBAL_SAMP01SURFADDR( 7),
260 GR3D_GLOBAL_SAMP01SURFADDR( 8),
261 GR3D_GLOBAL_SAMP01SURFADDR( 9),
262 GR3D_GLOBAL_SAMP01SURFADDR(10),
263 GR3D_GLOBAL_SAMP01SURFADDR(11),
264 GR3D_GLOBAL_SAMP01SURFADDR(12),
265 GR3D_GLOBAL_SAMP01SURFADDR(13),
266 GR3D_GLOBAL_SAMP01SURFADDR(14),
267 GR3D_GLOBAL_SAMP01SURFADDR(15),
268 GR3D_GLOBAL_SAMP23SURFADDR( 0),
269 GR3D_GLOBAL_SAMP23SURFADDR( 1),
270 GR3D_GLOBAL_SAMP23SURFADDR( 2),
271 GR3D_GLOBAL_SAMP23SURFADDR( 3),
272 GR3D_GLOBAL_SAMP23SURFADDR( 4),
273 GR3D_GLOBAL_SAMP23SURFADDR( 5),
274 GR3D_GLOBAL_SAMP23SURFADDR( 6),
275 GR3D_GLOBAL_SAMP23SURFADDR( 7),
276 GR3D_GLOBAL_SAMP23SURFADDR( 8),
277 GR3D_GLOBAL_SAMP23SURFADDR( 9),
278 GR3D_GLOBAL_SAMP23SURFADDR(10),
279 GR3D_GLOBAL_SAMP23SURFADDR(11),
280 GR3D_GLOBAL_SAMP23SURFADDR(12),
281 GR3D_GLOBAL_SAMP23SURFADDR(13),
282 GR3D_GLOBAL_SAMP23SURFADDR(14),
283 GR3D_GLOBAL_SAMP23SURFADDR(15),
286 static int gr3d_probe(struct platform_device
*pdev
)
288 struct device_node
*np
= pdev
->dev
.of_node
;
289 struct host1x_syncpt
**syncpts
;
294 gr3d
= devm_kzalloc(&pdev
->dev
, sizeof(*gr3d
), GFP_KERNEL
);
298 gr3d
->soc
= of_device_get_match_data(&pdev
->dev
);
300 syncpts
= devm_kzalloc(&pdev
->dev
, sizeof(*syncpts
), GFP_KERNEL
);
304 gr3d
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
305 if (IS_ERR(gr3d
->clk
)) {
306 dev_err(&pdev
->dev
, "cannot get clock\n");
307 return PTR_ERR(gr3d
->clk
);
310 gr3d
->rst
= devm_reset_control_get(&pdev
->dev
, "3d");
311 if (IS_ERR(gr3d
->rst
)) {
312 dev_err(&pdev
->dev
, "cannot get reset\n");
313 return PTR_ERR(gr3d
->rst
);
316 if (of_device_is_compatible(np
, "nvidia,tegra30-gr3d")) {
317 gr3d
->clk_secondary
= devm_clk_get(&pdev
->dev
, "3d2");
318 if (IS_ERR(gr3d
->clk_secondary
)) {
319 dev_err(&pdev
->dev
, "cannot get secondary clock\n");
320 return PTR_ERR(gr3d
->clk_secondary
);
323 gr3d
->rst_secondary
= devm_reset_control_get(&pdev
->dev
,
325 if (IS_ERR(gr3d
->rst_secondary
)) {
326 dev_err(&pdev
->dev
, "cannot get secondary reset\n");
327 return PTR_ERR(gr3d
->rst_secondary
);
331 err
= tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D
, gr3d
->clk
,
334 dev_err(&pdev
->dev
, "failed to power up 3D unit\n");
338 if (gr3d
->clk_secondary
) {
339 err
= tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1
,
341 gr3d
->rst_secondary
);
344 "failed to power up secondary 3D unit\n");
349 INIT_LIST_HEAD(&gr3d
->client
.base
.list
);
350 gr3d
->client
.base
.ops
= &gr3d_client_ops
;
351 gr3d
->client
.base
.dev
= &pdev
->dev
;
352 gr3d
->client
.base
.class = HOST1X_CLASS_GR3D
;
353 gr3d
->client
.base
.syncpts
= syncpts
;
354 gr3d
->client
.base
.num_syncpts
= 1;
356 INIT_LIST_HEAD(&gr3d
->client
.list
);
357 gr3d
->client
.version
= gr3d
->soc
->version
;
358 gr3d
->client
.ops
= &gr3d_ops
;
360 err
= host1x_client_register(&gr3d
->client
.base
);
362 dev_err(&pdev
->dev
, "failed to register host1x client: %d\n",
367 /* initialize address register map */
368 for (i
= 0; i
< ARRAY_SIZE(gr3d_addr_regs
); i
++)
369 set_bit(gr3d_addr_regs
[i
], gr3d
->addr_regs
);
371 platform_set_drvdata(pdev
, gr3d
);
376 static int gr3d_remove(struct platform_device
*pdev
)
378 struct gr3d
*gr3d
= platform_get_drvdata(pdev
);
381 err
= host1x_client_unregister(&gr3d
->client
.base
);
383 dev_err(&pdev
->dev
, "failed to unregister host1x client: %d\n",
388 if (gr3d
->clk_secondary
) {
389 tegra_powergate_power_off(TEGRA_POWERGATE_3D1
);
390 clk_disable_unprepare(gr3d
->clk_secondary
);
393 tegra_powergate_power_off(TEGRA_POWERGATE_3D
);
394 clk_disable_unprepare(gr3d
->clk
);
399 struct platform_driver tegra_gr3d_driver
= {
401 .name
= "tegra-gr3d",
402 .of_match_table
= tegra_gr3d_match
,
405 .remove
= gr3d_remove
,