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/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/reset.h>
16 #include <soc/tegra/pmc.h>
23 struct tegra_drm_client client
;
24 struct host1x_channel
*channel
;
25 struct clk
*clk_secondary
;
27 struct reset_control
*rst_secondary
;
28 struct reset_control
*rst
;
30 DECLARE_BITMAP(addr_regs
, GR3D_NUM_REGS
);
33 static inline struct gr3d
*to_gr3d(struct tegra_drm_client
*client
)
35 return container_of(client
, struct gr3d
, client
);
38 static int gr3d_init(struct host1x_client
*client
)
40 struct tegra_drm_client
*drm
= host1x_to_drm_client(client
);
41 struct drm_device
*dev
= dev_get_drvdata(client
->parent
);
42 unsigned long flags
= HOST1X_SYNCPT_HAS_BASE
;
43 struct gr3d
*gr3d
= to_gr3d(drm
);
45 gr3d
->channel
= host1x_channel_request(client
->dev
);
49 client
->syncpts
[0] = host1x_syncpt_request(client
->dev
, flags
);
50 if (!client
->syncpts
[0]) {
51 host1x_channel_free(gr3d
->channel
);
55 return tegra_drm_register_client(dev
->dev_private
, drm
);
58 static int gr3d_exit(struct host1x_client
*client
)
60 struct tegra_drm_client
*drm
= host1x_to_drm_client(client
);
61 struct drm_device
*dev
= dev_get_drvdata(client
->parent
);
62 struct gr3d
*gr3d
= to_gr3d(drm
);
65 err
= tegra_drm_unregister_client(dev
->dev_private
, drm
);
69 host1x_syncpt_free(client
->syncpts
[0]);
70 host1x_channel_free(gr3d
->channel
);
75 static const struct host1x_client_ops gr3d_client_ops
= {
80 static int gr3d_open_channel(struct tegra_drm_client
*client
,
81 struct tegra_drm_context
*context
)
83 struct gr3d
*gr3d
= to_gr3d(client
);
85 context
->channel
= host1x_channel_get(gr3d
->channel
);
86 if (!context
->channel
)
92 static void gr3d_close_channel(struct tegra_drm_context
*context
)
94 host1x_channel_put(context
->channel
);
97 static int gr3d_is_addr_reg(struct device
*dev
, u32
class, u32 offset
)
99 struct gr3d
*gr3d
= dev_get_drvdata(dev
);
102 case HOST1X_CLASS_HOST1X
:
108 case HOST1X_CLASS_GR3D
:
109 if (offset
>= GR3D_NUM_REGS
)
112 if (test_bit(offset
, gr3d
->addr_regs
))
121 static const struct tegra_drm_client_ops gr3d_ops
= {
122 .open_channel
= gr3d_open_channel
,
123 .close_channel
= gr3d_close_channel
,
124 .is_addr_reg
= gr3d_is_addr_reg
,
125 .submit
= tegra_drm_submit
,
128 static const struct of_device_id tegra_gr3d_match
[] = {
129 { .compatible
= "nvidia,tegra114-gr3d" },
130 { .compatible
= "nvidia,tegra30-gr3d" },
131 { .compatible
= "nvidia,tegra20-gr3d" },
134 MODULE_DEVICE_TABLE(of
, tegra_gr3d_match
);
136 static const u32 gr3d_addr_regs
[] = {
137 GR3D_IDX_ATTRIBUTE( 0),
138 GR3D_IDX_ATTRIBUTE( 1),
139 GR3D_IDX_ATTRIBUTE( 2),
140 GR3D_IDX_ATTRIBUTE( 3),
141 GR3D_IDX_ATTRIBUTE( 4),
142 GR3D_IDX_ATTRIBUTE( 5),
143 GR3D_IDX_ATTRIBUTE( 6),
144 GR3D_IDX_ATTRIBUTE( 7),
145 GR3D_IDX_ATTRIBUTE( 8),
146 GR3D_IDX_ATTRIBUTE( 9),
147 GR3D_IDX_ATTRIBUTE(10),
148 GR3D_IDX_ATTRIBUTE(11),
149 GR3D_IDX_ATTRIBUTE(12),
150 GR3D_IDX_ATTRIBUTE(13),
151 GR3D_IDX_ATTRIBUTE(14),
152 GR3D_IDX_ATTRIBUTE(15),
157 GR3D_TEX_TEX_ADDR( 0),
158 GR3D_TEX_TEX_ADDR( 1),
159 GR3D_TEX_TEX_ADDR( 2),
160 GR3D_TEX_TEX_ADDR( 3),
161 GR3D_TEX_TEX_ADDR( 4),
162 GR3D_TEX_TEX_ADDR( 5),
163 GR3D_TEX_TEX_ADDR( 6),
164 GR3D_TEX_TEX_ADDR( 7),
165 GR3D_TEX_TEX_ADDR( 8),
166 GR3D_TEX_TEX_ADDR( 9),
167 GR3D_TEX_TEX_ADDR(10),
168 GR3D_TEX_TEX_ADDR(11),
169 GR3D_TEX_TEX_ADDR(12),
170 GR3D_TEX_TEX_ADDR(13),
171 GR3D_TEX_TEX_ADDR(14),
172 GR3D_TEX_TEX_ADDR(15),
173 GR3D_DW_MEMORY_OUTPUT_ADDRESS
,
174 GR3D_GLOBAL_SURFADDR( 0),
175 GR3D_GLOBAL_SURFADDR( 1),
176 GR3D_GLOBAL_SURFADDR( 2),
177 GR3D_GLOBAL_SURFADDR( 3),
178 GR3D_GLOBAL_SURFADDR( 4),
179 GR3D_GLOBAL_SURFADDR( 5),
180 GR3D_GLOBAL_SURFADDR( 6),
181 GR3D_GLOBAL_SURFADDR( 7),
182 GR3D_GLOBAL_SURFADDR( 8),
183 GR3D_GLOBAL_SURFADDR( 9),
184 GR3D_GLOBAL_SURFADDR(10),
185 GR3D_GLOBAL_SURFADDR(11),
186 GR3D_GLOBAL_SURFADDR(12),
187 GR3D_GLOBAL_SURFADDR(13),
188 GR3D_GLOBAL_SURFADDR(14),
189 GR3D_GLOBAL_SURFADDR(15),
190 GR3D_GLOBAL_SPILLSURFADDR
,
191 GR3D_GLOBAL_SURFOVERADDR( 0),
192 GR3D_GLOBAL_SURFOVERADDR( 1),
193 GR3D_GLOBAL_SURFOVERADDR( 2),
194 GR3D_GLOBAL_SURFOVERADDR( 3),
195 GR3D_GLOBAL_SURFOVERADDR( 4),
196 GR3D_GLOBAL_SURFOVERADDR( 5),
197 GR3D_GLOBAL_SURFOVERADDR( 6),
198 GR3D_GLOBAL_SURFOVERADDR( 7),
199 GR3D_GLOBAL_SURFOVERADDR( 8),
200 GR3D_GLOBAL_SURFOVERADDR( 9),
201 GR3D_GLOBAL_SURFOVERADDR(10),
202 GR3D_GLOBAL_SURFOVERADDR(11),
203 GR3D_GLOBAL_SURFOVERADDR(12),
204 GR3D_GLOBAL_SURFOVERADDR(13),
205 GR3D_GLOBAL_SURFOVERADDR(14),
206 GR3D_GLOBAL_SURFOVERADDR(15),
207 GR3D_GLOBAL_SAMP01SURFADDR( 0),
208 GR3D_GLOBAL_SAMP01SURFADDR( 1),
209 GR3D_GLOBAL_SAMP01SURFADDR( 2),
210 GR3D_GLOBAL_SAMP01SURFADDR( 3),
211 GR3D_GLOBAL_SAMP01SURFADDR( 4),
212 GR3D_GLOBAL_SAMP01SURFADDR( 5),
213 GR3D_GLOBAL_SAMP01SURFADDR( 6),
214 GR3D_GLOBAL_SAMP01SURFADDR( 7),
215 GR3D_GLOBAL_SAMP01SURFADDR( 8),
216 GR3D_GLOBAL_SAMP01SURFADDR( 9),
217 GR3D_GLOBAL_SAMP01SURFADDR(10),
218 GR3D_GLOBAL_SAMP01SURFADDR(11),
219 GR3D_GLOBAL_SAMP01SURFADDR(12),
220 GR3D_GLOBAL_SAMP01SURFADDR(13),
221 GR3D_GLOBAL_SAMP01SURFADDR(14),
222 GR3D_GLOBAL_SAMP01SURFADDR(15),
223 GR3D_GLOBAL_SAMP23SURFADDR( 0),
224 GR3D_GLOBAL_SAMP23SURFADDR( 1),
225 GR3D_GLOBAL_SAMP23SURFADDR( 2),
226 GR3D_GLOBAL_SAMP23SURFADDR( 3),
227 GR3D_GLOBAL_SAMP23SURFADDR( 4),
228 GR3D_GLOBAL_SAMP23SURFADDR( 5),
229 GR3D_GLOBAL_SAMP23SURFADDR( 6),
230 GR3D_GLOBAL_SAMP23SURFADDR( 7),
231 GR3D_GLOBAL_SAMP23SURFADDR( 8),
232 GR3D_GLOBAL_SAMP23SURFADDR( 9),
233 GR3D_GLOBAL_SAMP23SURFADDR(10),
234 GR3D_GLOBAL_SAMP23SURFADDR(11),
235 GR3D_GLOBAL_SAMP23SURFADDR(12),
236 GR3D_GLOBAL_SAMP23SURFADDR(13),
237 GR3D_GLOBAL_SAMP23SURFADDR(14),
238 GR3D_GLOBAL_SAMP23SURFADDR(15),
241 static int gr3d_probe(struct platform_device
*pdev
)
243 struct device_node
*np
= pdev
->dev
.of_node
;
244 struct host1x_syncpt
**syncpts
;
249 gr3d
= devm_kzalloc(&pdev
->dev
, sizeof(*gr3d
), GFP_KERNEL
);
253 syncpts
= devm_kzalloc(&pdev
->dev
, sizeof(*syncpts
), GFP_KERNEL
);
257 gr3d
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
258 if (IS_ERR(gr3d
->clk
)) {
259 dev_err(&pdev
->dev
, "cannot get clock\n");
260 return PTR_ERR(gr3d
->clk
);
263 gr3d
->rst
= devm_reset_control_get(&pdev
->dev
, "3d");
264 if (IS_ERR(gr3d
->rst
)) {
265 dev_err(&pdev
->dev
, "cannot get reset\n");
266 return PTR_ERR(gr3d
->rst
);
269 if (of_device_is_compatible(np
, "nvidia,tegra30-gr3d")) {
270 gr3d
->clk_secondary
= devm_clk_get(&pdev
->dev
, "3d2");
271 if (IS_ERR(gr3d
->clk
)) {
272 dev_err(&pdev
->dev
, "cannot get secondary clock\n");
273 return PTR_ERR(gr3d
->clk
);
276 gr3d
->rst_secondary
= devm_reset_control_get(&pdev
->dev
,
278 if (IS_ERR(gr3d
->rst_secondary
)) {
279 dev_err(&pdev
->dev
, "cannot get secondary reset\n");
280 return PTR_ERR(gr3d
->rst_secondary
);
284 err
= tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D
, gr3d
->clk
,
287 dev_err(&pdev
->dev
, "failed to power up 3D unit\n");
291 if (gr3d
->clk_secondary
) {
292 err
= tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1
,
294 gr3d
->rst_secondary
);
297 "failed to power up secondary 3D unit\n");
302 INIT_LIST_HEAD(&gr3d
->client
.base
.list
);
303 gr3d
->client
.base
.ops
= &gr3d_client_ops
;
304 gr3d
->client
.base
.dev
= &pdev
->dev
;
305 gr3d
->client
.base
.class = HOST1X_CLASS_GR3D
;
306 gr3d
->client
.base
.syncpts
= syncpts
;
307 gr3d
->client
.base
.num_syncpts
= 1;
309 INIT_LIST_HEAD(&gr3d
->client
.list
);
310 gr3d
->client
.ops
= &gr3d_ops
;
312 err
= host1x_client_register(&gr3d
->client
.base
);
314 dev_err(&pdev
->dev
, "failed to register host1x client: %d\n",
319 /* initialize address register map */
320 for (i
= 0; i
< ARRAY_SIZE(gr3d_addr_regs
); i
++)
321 set_bit(gr3d_addr_regs
[i
], gr3d
->addr_regs
);
323 platform_set_drvdata(pdev
, gr3d
);
328 static int gr3d_remove(struct platform_device
*pdev
)
330 struct gr3d
*gr3d
= platform_get_drvdata(pdev
);
333 err
= host1x_client_unregister(&gr3d
->client
.base
);
335 dev_err(&pdev
->dev
, "failed to unregister host1x client: %d\n",
340 if (gr3d
->clk_secondary
) {
341 tegra_powergate_power_off(TEGRA_POWERGATE_3D1
);
342 clk_disable_unprepare(gr3d
->clk_secondary
);
345 tegra_powergate_power_off(TEGRA_POWERGATE_3D
);
346 clk_disable_unprepare(gr3d
->clk
);
351 struct platform_driver tegra_gr3d_driver
= {
353 .name
= "tegra-gr3d",
354 .of_match_table
= tegra_gr3d_match
,
357 .remove
= gr3d_remove
,