Skip to content

Commit 6b6776e

Browse files
digetxthierryreding
authored andcommitted
gpu: host1x: Add initial runtime PM and OPP support
Add runtime PM and OPP support to the Host1x driver. For the starter we will keep host1x always-on because dynamic power management require a major refactoring of the driver code since lot's of code paths are missing the RPM handling and we're going to remove some of these paths in the future. 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 d53830e commit 6b6776e

File tree

6 files changed

+164
-56
lines changed

6 files changed

+164
-56
lines changed

drivers/gpu/host1x/debug.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include <linux/debugfs.h>
10+
#include <linux/pm_runtime.h>
1011
#include <linux/seq_file.h>
1112
#include <linux/uaccess.h>
1213

@@ -52,6 +53,11 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
5253
{
5354
struct host1x *m = dev_get_drvdata(ch->dev->parent);
5455
struct output *o = data;
56+
int err;
57+
58+
err = pm_runtime_resume_and_get(m->dev);
59+
if (err < 0)
60+
return err;
5561

5662
mutex_lock(&ch->cdma.lock);
5763
mutex_lock(&debug_lock);
@@ -64,16 +70,23 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
6470
mutex_unlock(&debug_lock);
6571
mutex_unlock(&ch->cdma.lock);
6672

73+
pm_runtime_put(m->dev);
74+
6775
return 0;
6876
}
6977

7078
static void show_syncpts(struct host1x *m, struct output *o)
7179
{
7280
struct list_head *pos;
7381
unsigned int i;
82+
int err;
7483

7584
host1x_debug_output(o, "---- syncpts ----\n");
7685

86+
err = pm_runtime_resume_and_get(m->dev);
87+
if (err < 0)
88+
return;
89+
7790
for (i = 0; i < host1x_syncpt_nb_pts(m); i++) {
7891
u32 max = host1x_syncpt_read_max(m->syncpt + i);
7992
u32 min = host1x_syncpt_load(m->syncpt + i);
@@ -101,6 +114,8 @@ static void show_syncpts(struct host1x *m, struct output *o)
101114
base_val);
102115
}
103116

117+
pm_runtime_put(m->dev);
118+
104119
host1x_debug_output(o, "\n");
105120
}
106121

drivers/gpu/host1x/dev.c

Lines changed: 123 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@
66
*/
77

88
#include <linux/clk.h>
9+
#include <linux/delay.h>
910
#include <linux/dma-mapping.h>
1011
#include <linux/io.h>
1112
#include <linux/list.h>
1213
#include <linux/module.h>
1314
#include <linux/of_device.h>
1415
#include <linux/of.h>
16+
#include <linux/pm_runtime.h>
1517
#include <linux/slab.h>
1618

19+
#include <soc/tegra/common.h>
20+
1721
#define CREATE_TRACE_POINTS
1822
#include <trace/events/host1x.h>
1923
#undef CREATE_TRACE_POINTS
@@ -208,6 +212,9 @@ static void host1x_setup_sid_table(struct host1x *host)
208212
const struct host1x_info *info = host->info;
209213
unsigned int i;
210214

215+
if (!info->has_hypervisor)
216+
return;
217+
211218
for (i = 0; i < info->num_sid_entries; i++) {
212219
const struct host1x_sid_entry *entry = &info->sid_table[i];
213220

@@ -365,6 +372,27 @@ static void host1x_iommu_exit(struct host1x *host)
365372
}
366373
}
367374

375+
static int host1x_get_resets(struct host1x *host)
376+
{
377+
int err;
378+
379+
host->resets[0].id = "mc";
380+
host->resets[1].id = "host1x";
381+
host->nresets = ARRAY_SIZE(host->resets);
382+
383+
err = devm_reset_control_bulk_get_optional_exclusive_released(
384+
host->dev, host->nresets, host->resets);
385+
if (err) {
386+
dev_err(host->dev, "failed to get reset: %d\n", err);
387+
return err;
388+
}
389+
390+
if (WARN_ON(!host->resets[1].rstc))
391+
return -ENOENT;
392+
393+
return 0;
394+
}
395+
368396
static int host1x_probe(struct platform_device *pdev)
369397
{
370398
struct host1x *host;
@@ -442,12 +470,9 @@ static int host1x_probe(struct platform_device *pdev)
442470
return err;
443471
}
444472

445-
host->rst = devm_reset_control_get(&pdev->dev, "host1x");
446-
if (IS_ERR(host->rst)) {
447-
err = PTR_ERR(host->rst);
448-
dev_err(&pdev->dev, "failed to get reset: %d\n", err);
473+
err = host1x_get_resets(host);
474+
if (err)
449475
return err;
450-
}
451476

452477
err = host1x_iommu_init(host);
453478
if (err < 0) {
@@ -462,22 +487,10 @@ static int host1x_probe(struct platform_device *pdev)
462487
goto iommu_exit;
463488
}
464489

465-
err = clk_prepare_enable(host->clk);
466-
if (err < 0) {
467-
dev_err(&pdev->dev, "failed to enable clock\n");
468-
goto free_channels;
469-
}
470-
471-
err = reset_control_deassert(host->rst);
472-
if (err < 0) {
473-
dev_err(&pdev->dev, "failed to deassert reset: %d\n", err);
474-
goto unprepare_disable;
475-
}
476-
477490
err = host1x_syncpt_init(host);
478491
if (err) {
479492
dev_err(&pdev->dev, "failed to initialize syncpts\n");
480-
goto reset_assert;
493+
goto free_channels;
481494
}
482495

483496
err = host1x_intr_init(host, syncpt_irq);
@@ -486,10 +499,18 @@ static int host1x_probe(struct platform_device *pdev)
486499
goto deinit_syncpt;
487500
}
488501

489-
host1x_debug_init(host);
502+
pm_runtime_enable(&pdev->dev);
503+
504+
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
505+
if (err)
506+
goto pm_disable;
490507

491-
if (host->info->has_hypervisor)
492-
host1x_setup_sid_table(host);
508+
/* the driver's code isn't ready yet for the dynamic RPM */
509+
err = pm_runtime_resume_and_get(&pdev->dev);
510+
if (err)
511+
goto pm_disable;
512+
513+
host1x_debug_init(host);
493514

494515
err = host1x_register(host);
495516
if (err < 0)
@@ -505,13 +526,14 @@ static int host1x_probe(struct platform_device *pdev)
505526
host1x_unregister(host);
506527
deinit_debugfs:
507528
host1x_debug_deinit(host);
529+
530+
pm_runtime_put_sync_suspend(&pdev->dev);
531+
pm_disable:
532+
pm_runtime_disable(&pdev->dev);
533+
508534
host1x_intr_deinit(host);
509535
deinit_syncpt:
510536
host1x_syncpt_deinit(host);
511-
reset_assert:
512-
reset_control_assert(host->rst);
513-
unprepare_disable:
514-
clk_disable_unprepare(host->clk);
515537
free_channels:
516538
host1x_channel_list_free(&host->channel_list);
517539
iommu_exit:
@@ -526,20 +548,94 @@ static int host1x_remove(struct platform_device *pdev)
526548

527549
host1x_unregister(host);
528550
host1x_debug_deinit(host);
551+
552+
pm_runtime_force_suspend(&pdev->dev);
553+
529554
host1x_intr_deinit(host);
530555
host1x_syncpt_deinit(host);
531-
reset_control_assert(host->rst);
532-
clk_disable_unprepare(host->clk);
533556
host1x_iommu_exit(host);
534557
host1x_bo_cache_destroy(&host->cache);
535558

536559
return 0;
537560
}
538561

562+
static int __maybe_unused host1x_runtime_suspend(struct device *dev)
563+
{
564+
struct host1x *host = dev_get_drvdata(dev);
565+
int err;
566+
567+
host1x_intr_stop(host);
568+
host1x_syncpt_save(host);
569+
570+
err = reset_control_bulk_assert(host->nresets, host->resets);
571+
if (err) {
572+
dev_err(dev, "failed to assert reset: %d\n", err);
573+
goto resume_host1x;
574+
}
575+
576+
usleep_range(1000, 2000);
577+
578+
clk_disable_unprepare(host->clk);
579+
reset_control_bulk_release(host->nresets, host->resets);
580+
581+
return 0;
582+
583+
resume_host1x:
584+
host1x_setup_sid_table(host);
585+
host1x_syncpt_restore(host);
586+
host1x_intr_start(host);
587+
588+
return err;
589+
}
590+
591+
static int __maybe_unused host1x_runtime_resume(struct device *dev)
592+
{
593+
struct host1x *host = dev_get_drvdata(dev);
594+
int err;
595+
596+
err = reset_control_bulk_acquire(host->nresets, host->resets);
597+
if (err) {
598+
dev_err(dev, "failed to acquire reset: %d\n", err);
599+
return err;
600+
}
601+
602+
err = clk_prepare_enable(host->clk);
603+
if (err) {
604+
dev_err(dev, "failed to enable clock: %d\n", err);
605+
goto release_reset;
606+
}
607+
608+
err = reset_control_bulk_deassert(host->nresets, host->resets);
609+
if (err < 0) {
610+
dev_err(dev, "failed to deassert reset: %d\n", err);
611+
goto disable_clk;
612+
}
613+
614+
host1x_setup_sid_table(host);
615+
host1x_syncpt_restore(host);
616+
host1x_intr_start(host);
617+
618+
return 0;
619+
620+
disable_clk:
621+
clk_disable_unprepare(host->clk);
622+
release_reset:
623+
reset_control_bulk_release(host->nresets, host->resets);
624+
625+
return err;
626+
}
627+
628+
static const struct dev_pm_ops host1x_pm_ops = {
629+
SET_RUNTIME_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume,
630+
NULL)
631+
/* TODO: add system suspend-resume once driver will be ready for that */
632+
};
633+
539634
static struct platform_driver tegra_host1x_driver = {
540635
.driver = {
541636
.name = "tegra-host1x",
542637
.of_match_table = host1x_of_match,
638+
.pm = &host1x_pm_ops,
543639
},
544640
.probe = host1x_probe,
545641
.remove = host1x_remove,

drivers/gpu/host1x/dev.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ struct host1x {
118118
struct host1x_syncpt_base *bases;
119119
struct device *dev;
120120
struct clk *clk;
121-
struct reset_control *rst;
121+
struct reset_control_bulk_data resets[2];
122+
unsigned int nresets;
122123

123124
struct iommu_group *group;
124125
struct iommu_domain *domain;

drivers/gpu/host1x/hw/channel_hw.c

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,27 @@ static void host1x_channel_set_streamid(struct host1x_channel *channel)
159159
#endif
160160
}
161161

162+
static void host1x_enable_gather_filter(struct host1x_channel *ch)
163+
{
164+
#if HOST1X_HW >= 6
165+
struct host1x *host = dev_get_drvdata(ch->dev->parent);
166+
u32 val;
167+
168+
if (!host->hv_regs)
169+
return;
170+
171+
val = host1x_hypervisor_readl(
172+
host, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32));
173+
val |= BIT(ch->id % 32);
174+
host1x_hypervisor_writel(
175+
host, val, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32));
176+
#elif HOST1X_HW >= 4
177+
host1x_ch_writel(ch,
178+
HOST1X_CHANNEL_CHANNELCTRL_KERNEL_FILTER_GBUFFER(1),
179+
HOST1X_CHANNEL_CHANNELCTRL);
180+
#endif
181+
}
182+
162183
static int channel_submit(struct host1x_job *job)
163184
{
164185
struct host1x_channel *ch = job->channel;
@@ -190,6 +211,7 @@ static int channel_submit(struct host1x_job *job)
190211
}
191212

192213
host1x_channel_set_streamid(ch);
214+
host1x_enable_gather_filter(ch);
193215

194216
/* begin a CDMA submit */
195217
err = host1x_cdma_begin(&ch->cdma, job);
@@ -249,27 +271,6 @@ static int channel_submit(struct host1x_job *job)
249271
return err;
250272
}
251273

252-
static void enable_gather_filter(struct host1x *host,
253-
struct host1x_channel *ch)
254-
{
255-
#if HOST1X_HW >= 6
256-
u32 val;
257-
258-
if (!host->hv_regs)
259-
return;
260-
261-
val = host1x_hypervisor_readl(
262-
host, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32));
263-
val |= BIT(ch->id % 32);
264-
host1x_hypervisor_writel(
265-
host, val, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32));
266-
#elif HOST1X_HW >= 4
267-
host1x_ch_writel(ch,
268-
HOST1X_CHANNEL_CHANNELCTRL_KERNEL_FILTER_GBUFFER(1),
269-
HOST1X_CHANNEL_CHANNELCTRL);
270-
#endif
271-
}
272-
273274
static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev,
274275
unsigned int index)
275276
{
@@ -278,7 +279,6 @@ static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev,
278279
#else
279280
ch->regs = dev->regs + index * 0x100;
280281
#endif
281-
enable_gather_filter(dev, ch);
282282
return 0;
283283
}
284284

drivers/gpu/host1x/intr.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,14 +297,11 @@ int host1x_intr_init(struct host1x *host, unsigned int irq_sync)
297297
"host1x_sp_%02u", id);
298298
}
299299

300-
host1x_intr_start(host);
301-
302300
return 0;
303301
}
304302

305303
void host1x_intr_deinit(struct host1x *host)
306304
{
307-
host1x_intr_stop(host);
308305
}
309306

310307
void host1x_intr_start(struct host1x *host)

0 commit comments

Comments
 (0)