2 * Copyright (c) 2012-2013, NVIDIA Corporation.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
10 #include <linux/iommu.h>
11 #include <linux/of_device.h>
22 struct iommu_group
*group
;
23 struct tegra_drm_client client
;
24 struct host1x_channel
*channel
;
27 const struct gr2d_soc
*soc
;
29 DECLARE_BITMAP(addr_regs
, GR2D_NUM_REGS
);
32 static inline struct gr2d
*to_gr2d(struct tegra_drm_client
*client
)
34 return container_of(client
, struct gr2d
, client
);
37 static int gr2d_init(struct host1x_client
*client
)
39 struct tegra_drm_client
*drm
= host1x_to_drm_client(client
);
40 struct drm_device
*dev
= dev_get_drvdata(client
->parent
);
41 unsigned long flags
= HOST1X_SYNCPT_HAS_BASE
;
42 struct gr2d
*gr2d
= to_gr2d(drm
);
45 gr2d
->channel
= host1x_channel_request(client
->dev
);
49 client
->syncpts
[0] = host1x_syncpt_request(client
, flags
);
50 if (!client
->syncpts
[0]) {
52 dev_err(client
->dev
, "failed to request syncpoint: %d\n", err
);
56 gr2d
->group
= host1x_client_iommu_attach(client
, false);
57 if (IS_ERR(gr2d
->group
)) {
58 err
= PTR_ERR(gr2d
->group
);
59 dev_err(client
->dev
, "failed to attach to domain: %d\n", err
);
63 err
= tegra_drm_register_client(dev
->dev_private
, drm
);
65 dev_err(client
->dev
, "failed to register client: %d\n", err
);
72 host1x_client_iommu_detach(client
, gr2d
->group
);
74 host1x_syncpt_free(client
->syncpts
[0]);
76 host1x_channel_put(gr2d
->channel
);
80 static int gr2d_exit(struct host1x_client
*client
)
82 struct tegra_drm_client
*drm
= host1x_to_drm_client(client
);
83 struct drm_device
*dev
= dev_get_drvdata(client
->parent
);
84 struct tegra_drm
*tegra
= dev
->dev_private
;
85 struct gr2d
*gr2d
= to_gr2d(drm
);
88 err
= tegra_drm_unregister_client(tegra
, drm
);
92 host1x_client_iommu_detach(client
, gr2d
->group
);
93 host1x_syncpt_free(client
->syncpts
[0]);
94 host1x_channel_put(gr2d
->channel
);
99 static const struct host1x_client_ops gr2d_client_ops
= {
104 static int gr2d_open_channel(struct tegra_drm_client
*client
,
105 struct tegra_drm_context
*context
)
107 struct gr2d
*gr2d
= to_gr2d(client
);
109 context
->channel
= host1x_channel_get(gr2d
->channel
);
110 if (!context
->channel
)
116 static void gr2d_close_channel(struct tegra_drm_context
*context
)
118 host1x_channel_put(context
->channel
);
121 static int gr2d_is_addr_reg(struct device
*dev
, u32
class, u32 offset
)
123 struct gr2d
*gr2d
= dev_get_drvdata(dev
);
126 case HOST1X_CLASS_HOST1X
:
132 case HOST1X_CLASS_GR2D
:
133 case HOST1X_CLASS_GR2D_SB
:
134 if (offset
>= GR2D_NUM_REGS
)
137 if (test_bit(offset
, gr2d
->addr_regs
))
146 static int gr2d_is_valid_class(u32
class)
148 return (class == HOST1X_CLASS_GR2D
||
149 class == HOST1X_CLASS_GR2D_SB
);
152 static const struct tegra_drm_client_ops gr2d_ops
= {
153 .open_channel
= gr2d_open_channel
,
154 .close_channel
= gr2d_close_channel
,
155 .is_addr_reg
= gr2d_is_addr_reg
,
156 .is_valid_class
= gr2d_is_valid_class
,
157 .submit
= tegra_drm_submit
,
160 static const struct gr2d_soc tegra20_gr2d_soc
= {
164 static const struct gr2d_soc tegra30_gr2d_soc
= {
168 static const struct of_device_id gr2d_match
[] = {
169 { .compatible
= "nvidia,tegra30-gr2d", .data
= &tegra20_gr2d_soc
},
170 { .compatible
= "nvidia,tegra20-gr2d", .data
= &tegra30_gr2d_soc
},
173 MODULE_DEVICE_TABLE(of
, gr2d_match
);
175 static const u32 gr2d_addr_regs
[] = {
184 GR2D_SRC_BASE_ADDR_SB
,
185 GR2D_DSTA_BASE_ADDR_SB
,
186 GR2D_DSTB_BASE_ADDR_SB
,
187 GR2D_UA_BASE_ADDR_SB
,
188 GR2D_VA_BASE_ADDR_SB
,
191 static int gr2d_probe(struct platform_device
*pdev
)
193 struct device
*dev
= &pdev
->dev
;
194 struct host1x_syncpt
**syncpts
;
199 gr2d
= devm_kzalloc(dev
, sizeof(*gr2d
), GFP_KERNEL
);
203 gr2d
->soc
= of_device_get_match_data(dev
);
205 syncpts
= devm_kzalloc(dev
, sizeof(*syncpts
), GFP_KERNEL
);
209 gr2d
->clk
= devm_clk_get(dev
, NULL
);
210 if (IS_ERR(gr2d
->clk
)) {
211 dev_err(dev
, "cannot get clock\n");
212 return PTR_ERR(gr2d
->clk
);
215 err
= clk_prepare_enable(gr2d
->clk
);
217 dev_err(dev
, "cannot turn on clock\n");
221 INIT_LIST_HEAD(&gr2d
->client
.base
.list
);
222 gr2d
->client
.base
.ops
= &gr2d_client_ops
;
223 gr2d
->client
.base
.dev
= dev
;
224 gr2d
->client
.base
.class = HOST1X_CLASS_GR2D
;
225 gr2d
->client
.base
.syncpts
= syncpts
;
226 gr2d
->client
.base
.num_syncpts
= 1;
228 INIT_LIST_HEAD(&gr2d
->client
.list
);
229 gr2d
->client
.version
= gr2d
->soc
->version
;
230 gr2d
->client
.ops
= &gr2d_ops
;
232 err
= host1x_client_register(&gr2d
->client
.base
);
234 dev_err(dev
, "failed to register host1x client: %d\n", err
);
235 clk_disable_unprepare(gr2d
->clk
);
239 /* initialize address register map */
240 for (i
= 0; i
< ARRAY_SIZE(gr2d_addr_regs
); i
++)
241 set_bit(gr2d_addr_regs
[i
], gr2d
->addr_regs
);
243 platform_set_drvdata(pdev
, gr2d
);
248 static int gr2d_remove(struct platform_device
*pdev
)
250 struct gr2d
*gr2d
= platform_get_drvdata(pdev
);
253 err
= host1x_client_unregister(&gr2d
->client
.base
);
255 dev_err(&pdev
->dev
, "failed to unregister host1x client: %d\n",
260 clk_disable_unprepare(gr2d
->clk
);
265 struct platform_driver tegra_gr2d_driver
= {
267 .name
= "tegra-gr2d",
268 .of_match_table
= gr2d_match
,
271 .remove
= gr2d_remove
,