Skip to content

Commit e4e4a71

Browse files
digetxthierryreding
authored andcommitted
drm/tegra: gr2d: Support generic power domain and runtime PM
Add runtime power management and support generic power domains. Reviewed-by: Ulf Hansson <[email protected]> Tested-by: Peter Geis <[email protected]> # Ouya T30 Tested-by: Paul Fertser <[email protected]> # PAZ00 T20 Tested-by: Nicolas Chauvet <[email protected]> # PAZ00 T20 and TK1 T124 Tested-by: Matt Merhar <[email protected]> # Ouya T30 Signed-off-by: Dmitry Osipenko <[email protected]> Signed-off-by: Thierry Reding <[email protected]>
1 parent 6efdde0 commit e4e4a71

File tree

1 file changed

+148
-36
lines changed

1 file changed

+148
-36
lines changed

drivers/gpu/drm/tegra/gr2d.c

Lines changed: 148 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,33 @@
88
#include <linux/iommu.h>
99
#include <linux/module.h>
1010
#include <linux/of_device.h>
11+
#include <linux/pm_runtime.h>
1112
#include <linux/reset.h>
1213

14+
#include <soc/tegra/common.h>
15+
1316
#include "drm.h"
1417
#include "gem.h"
1518
#include "gr2d.h"
1619

20+
enum {
21+
RST_MC,
22+
RST_GR2D,
23+
RST_GR2D_MAX,
24+
};
25+
1726
struct gr2d_soc {
1827
unsigned int version;
1928
};
2029

2130
struct gr2d {
2231
struct tegra_drm_client client;
2332
struct host1x_channel *channel;
24-
struct reset_control *rst;
2533
struct clk *clk;
2634

35+
struct reset_control_bulk_data resets[RST_GR2D_MAX];
36+
unsigned int nresets;
37+
2738
const struct gr2d_soc *soc;
2839

2940
DECLARE_BITMAP(addr_regs, GR2D_NUM_REGS);
@@ -59,15 +70,22 @@ static int gr2d_init(struct host1x_client *client)
5970
goto free;
6071
}
6172

73+
pm_runtime_enable(client->dev);
74+
pm_runtime_use_autosuspend(client->dev);
75+
pm_runtime_set_autosuspend_delay(client->dev, 200);
76+
6277
err = tegra_drm_register_client(dev->dev_private, drm);
6378
if (err < 0) {
6479
dev_err(client->dev, "failed to register client: %d\n", err);
65-
goto detach;
80+
goto disable_rpm;
6681
}
6782

6883
return 0;
6984

70-
detach:
85+
disable_rpm:
86+
pm_runtime_dont_use_autosuspend(client->dev);
87+
pm_runtime_force_suspend(client->dev);
88+
7189
host1x_client_iommu_detach(client);
7290
free:
7391
host1x_syncpt_put(client->syncpts[0]);
@@ -88,10 +106,15 @@ static int gr2d_exit(struct host1x_client *client)
88106
if (err < 0)
89107
return err;
90108

109+
pm_runtime_dont_use_autosuspend(client->dev);
110+
pm_runtime_force_suspend(client->dev);
111+
91112
host1x_client_iommu_detach(client);
92113
host1x_syncpt_put(client->syncpts[0]);
93114
host1x_channel_put(gr2d->channel);
94115

116+
gr2d->channel = NULL;
117+
95118
return 0;
96119
}
97120

@@ -104,17 +127,25 @@ static int gr2d_open_channel(struct tegra_drm_client *client,
104127
struct tegra_drm_context *context)
105128
{
106129
struct gr2d *gr2d = to_gr2d(client);
130+
int err;
131+
132+
err = pm_runtime_resume_and_get(client->base.dev);
133+
if (err)
134+
return err;
107135

108136
context->channel = host1x_channel_get(gr2d->channel);
109-
if (!context->channel)
137+
if (!context->channel) {
138+
pm_runtime_put(client->base.dev);
110139
return -ENOMEM;
140+
}
111141

112142
return 0;
113143
}
114144

115145
static void gr2d_close_channel(struct tegra_drm_context *context)
116146
{
117147
host1x_channel_put(context->channel);
148+
pm_runtime_put(context->client->base.dev);
118149
}
119150

120151
static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset)
@@ -193,6 +224,27 @@ static const u32 gr2d_addr_regs[] = {
193224
GR2D_VA_BASE_ADDR_SB,
194225
};
195226

227+
static int gr2d_get_resets(struct device *dev, struct gr2d *gr2d)
228+
{
229+
int err;
230+
231+
gr2d->resets[RST_MC].id = "mc";
232+
gr2d->resets[RST_GR2D].id = "2d";
233+
gr2d->nresets = RST_GR2D_MAX;
234+
235+
err = devm_reset_control_bulk_get_optional_exclusive_released(
236+
dev, gr2d->nresets, gr2d->resets);
237+
if (err) {
238+
dev_err(dev, "failed to get reset: %d\n", err);
239+
return err;
240+
}
241+
242+
if (WARN_ON(!gr2d->resets[RST_GR2D].rstc))
243+
return -ENOENT;
244+
245+
return 0;
246+
}
247+
196248
static int gr2d_probe(struct platform_device *pdev)
197249
{
198250
struct device *dev = &pdev->dev;
@@ -205,37 +257,23 @@ static int gr2d_probe(struct platform_device *pdev)
205257
if (!gr2d)
206258
return -ENOMEM;
207259

260+
platform_set_drvdata(pdev, gr2d);
261+
208262
gr2d->soc = of_device_get_match_data(dev);
209263

210264
syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
211265
if (!syncpts)
212266
return -ENOMEM;
213267

214-
gr2d->rst = devm_reset_control_get(dev, NULL);
215-
if (IS_ERR(gr2d->rst)) {
216-
dev_err(dev, "cannot get reset\n");
217-
return PTR_ERR(gr2d->rst);
218-
}
219-
220268
gr2d->clk = devm_clk_get(dev, NULL);
221269
if (IS_ERR(gr2d->clk)) {
222270
dev_err(dev, "cannot get clock\n");
223271
return PTR_ERR(gr2d->clk);
224272
}
225273

226-
err = clk_prepare_enable(gr2d->clk);
227-
if (err) {
228-
dev_err(dev, "cannot turn on clock\n");
274+
err = gr2d_get_resets(dev, gr2d);
275+
if (err)
229276
return err;
230-
}
231-
232-
usleep_range(2000, 4000);
233-
234-
err = reset_control_deassert(gr2d->rst);
235-
if (err < 0) {
236-
dev_err(dev, "failed to deassert reset: %d\n", err);
237-
goto disable_clk;
238-
}
239277

240278
INIT_LIST_HEAD(&gr2d->client.base.list);
241279
gr2d->client.base.ops = &gr2d_client_ops;
@@ -248,26 +286,21 @@ static int gr2d_probe(struct platform_device *pdev)
248286
gr2d->client.version = gr2d->soc->version;
249287
gr2d->client.ops = &gr2d_ops;
250288

289+
err = devm_tegra_core_dev_init_opp_table_common(dev);
290+
if (err)
291+
return err;
292+
251293
err = host1x_client_register(&gr2d->client.base);
252294
if (err < 0) {
253295
dev_err(dev, "failed to register host1x client: %d\n", err);
254-
goto assert_rst;
296+
return err;
255297
}
256298

257299
/* initialize address register map */
258300
for (i = 0; i < ARRAY_SIZE(gr2d_addr_regs); i++)
259301
set_bit(gr2d_addr_regs[i], gr2d->addr_regs);
260302

261-
platform_set_drvdata(pdev, gr2d);
262-
263303
return 0;
264-
265-
assert_rst:
266-
(void)reset_control_assert(gr2d->rst);
267-
disable_clk:
268-
clk_disable_unprepare(gr2d->clk);
269-
270-
return err;
271304
}
272305

273306
static int gr2d_remove(struct platform_device *pdev)
@@ -282,21 +315,100 @@ static int gr2d_remove(struct platform_device *pdev)
282315
return err;
283316
}
284317

285-
err = reset_control_assert(gr2d->rst);
286-
if (err < 0)
287-
dev_err(&pdev->dev, "failed to assert reset: %d\n", err);
318+
return 0;
319+
}
288320

289-
usleep_range(2000, 4000);
321+
static int __maybe_unused gr2d_runtime_suspend(struct device *dev)
322+
{
323+
struct gr2d *gr2d = dev_get_drvdata(dev);
324+
int err;
325+
326+
host1x_channel_stop(gr2d->channel);
327+
reset_control_bulk_release(gr2d->nresets, gr2d->resets);
328+
329+
/*
330+
* GR2D module shouldn't be reset while hardware is idling, otherwise
331+
* host1x's cmdproc will stuck on trying to access any G2 register
332+
* after reset. GR2D module could be either hot-reset or reset after
333+
* power-gating of the HEG partition. Hence we will put in reset only
334+
* the memory client part of the module, the HEG GENPD will take care
335+
* of resetting GR2D module across power-gating.
336+
*
337+
* On Tegra20 there is no HEG partition, but it's okay to have
338+
* undetermined h/w state since userspace is expected to reprogram
339+
* the state on each job submission anyways.
340+
*/
341+
err = reset_control_acquire(gr2d->resets[RST_MC].rstc);
342+
if (err) {
343+
dev_err(dev, "failed to acquire MC reset: %d\n", err);
344+
goto acquire_reset;
345+
}
346+
347+
err = reset_control_assert(gr2d->resets[RST_MC].rstc);
348+
reset_control_release(gr2d->resets[RST_MC].rstc);
349+
if (err) {
350+
dev_err(dev, "failed to assert MC reset: %d\n", err);
351+
goto acquire_reset;
352+
}
290353

291354
clk_disable_unprepare(gr2d->clk);
292355

293356
return 0;
357+
358+
acquire_reset:
359+
reset_control_bulk_acquire(gr2d->nresets, gr2d->resets);
360+
reset_control_bulk_deassert(gr2d->nresets, gr2d->resets);
361+
362+
return err;
363+
}
364+
365+
static int __maybe_unused gr2d_runtime_resume(struct device *dev)
366+
{
367+
struct gr2d *gr2d = dev_get_drvdata(dev);
368+
int err;
369+
370+
err = reset_control_bulk_acquire(gr2d->nresets, gr2d->resets);
371+
if (err) {
372+
dev_err(dev, "failed to acquire reset: %d\n", err);
373+
return err;
374+
}
375+
376+
err = clk_prepare_enable(gr2d->clk);
377+
if (err) {
378+
dev_err(dev, "failed to enable clock: %d\n", err);
379+
goto release_reset;
380+
}
381+
382+
usleep_range(2000, 4000);
383+
384+
/* this is a reset array which deasserts both 2D MC and 2D itself */
385+
err = reset_control_bulk_deassert(gr2d->nresets, gr2d->resets);
386+
if (err) {
387+
dev_err(dev, "failed to deassert reset: %d\n", err);
388+
goto disable_clk;
389+
}
390+
391+
return 0;
392+
393+
disable_clk:
394+
clk_disable_unprepare(gr2d->clk);
395+
release_reset:
396+
reset_control_bulk_release(gr2d->nresets, gr2d->resets);
397+
398+
return err;
294399
}
295400

401+
static const struct dev_pm_ops tegra_gr2d_pm = {
402+
SET_RUNTIME_PM_OPS(gr2d_runtime_suspend, gr2d_runtime_resume, NULL)
403+
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
404+
pm_runtime_force_resume)
405+
};
406+
296407
struct platform_driver tegra_gr2d_driver = {
297408
.driver = {
298409
.name = "tegra-gr2d",
299410
.of_match_table = gr2d_match,
411+
.pm = &tegra_gr2d_pm,
300412
},
301413
.probe = gr2d_probe,
302414
.remove = gr2d_remove,

0 commit comments

Comments
 (0)