diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index a5b4fddc..b36beb52 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/spinlock.h> | 42 | #include <linux/spinlock.h> |
43 | #include <linux/tegra-powergate.h> | 43 | #include <linux/tegra-powergate.h> |
44 | #include <linux/tegra_pm_domains.h> | 44 | #include <linux/tegra_pm_domains.h> |
45 | #include <linux/clk/tegra.h> | ||
45 | 46 | ||
46 | #include <linux/sched.h> | 47 | #include <linux/sched.h> |
47 | #include <linux/input-cfboost.h> | 48 | #include <linux/input-cfboost.h> |
@@ -1610,6 +1611,79 @@ void gk20a_reset(struct gk20a *g, u32 units) | |||
1610 | gk20a_enable(g, units); | 1611 | gk20a_enable(g, units); |
1611 | } | 1612 | } |
1612 | 1613 | ||
1614 | /** | ||
1615 | * gk20a_do_idle() - force the GPU to idle and railgate | ||
1616 | * | ||
1617 | * In success, this call MUST be balanced by caller with gk20a_do_unidle() | ||
1618 | */ | ||
1619 | int gk20a_do_idle(void) | ||
1620 | { | ||
1621 | struct platform_device *pdev = to_platform_device( | ||
1622 | bus_find_device_by_name(&platform_bus_type, | ||
1623 | NULL, "gk20a.0")); | ||
1624 | struct gk20a *g = get_gk20a(pdev); | ||
1625 | struct gk20a_platform *platform = dev_get_drvdata(&pdev->dev); | ||
1626 | struct fifo_gk20a *f = &g->fifo; | ||
1627 | unsigned long timeout = jiffies + msecs_to_jiffies(200); | ||
1628 | int chid, ref_cnt; | ||
1629 | |||
1630 | if (!platform->can_railgate) | ||
1631 | return -ENOSYS; | ||
1632 | |||
1633 | /* acquire busy lock to block other busy() calls */ | ||
1634 | down_write(&g->busy_lock); | ||
1635 | |||
1636 | /* prevent suspend by incrementing usage counter */ | ||
1637 | pm_runtime_get_noresume(&pdev->dev); | ||
1638 | |||
1639 | /* check and wait until GPU is idle (with a timeout) */ | ||
1640 | pm_runtime_barrier(&pdev->dev); | ||
1641 | |||
1642 | for (chid = 0; chid < f->num_channels; chid++) | ||
1643 | if (gk20a_wait_channel_idle(&f->channel[chid])) | ||
1644 | goto fail; | ||
1645 | |||
1646 | do { | ||
1647 | mdelay(1); | ||
1648 | ref_cnt = atomic_read(&pdev->dev.power.usage_count); | ||
1649 | } while (ref_cnt != 1 && time_before(jiffies, timeout)); | ||
1650 | |||
1651 | if (ref_cnt != 1) | ||
1652 | goto fail; | ||
1653 | |||
1654 | /* | ||
1655 | * if GPU is now idle, we will have only one ref count | ||
1656 | * drop this ref which will rail gate the GPU | ||
1657 | */ | ||
1658 | pm_runtime_put_sync(&pdev->dev); | ||
1659 | |||
1660 | /* add sufficient delay to allow GPU to rail gate */ | ||
1661 | mdelay(platform->railgate_delay + 100); | ||
1662 | |||
1663 | return 0; | ||
1664 | |||
1665 | fail: | ||
1666 | pm_runtime_put_noidle(&pdev->dev); | ||
1667 | up_write(&g->busy_lock); | ||
1668 | return -EBUSY; | ||
1669 | } | ||
1670 | |||
1671 | /** | ||
1672 | * gk20a_do_unidle() - unblock all the tasks blocked by gk20a_do_idle() | ||
1673 | */ | ||
1674 | int gk20a_do_unidle(void) | ||
1675 | { | ||
1676 | struct platform_device *pdev = to_platform_device( | ||
1677 | bus_find_device_by_name(&platform_bus_type, | ||
1678 | NULL, "gk20a.0")); | ||
1679 | struct gk20a *g = get_gk20a(pdev); | ||
1680 | |||
1681 | /* release the lock and open up all other busy() calls */ | ||
1682 | up_write(&g->busy_lock); | ||
1683 | |||
1684 | return 0; | ||
1685 | } | ||
1686 | |||
1613 | int gk20a_init_gpu_characteristics(struct gk20a *g) | 1687 | int gk20a_init_gpu_characteristics(struct gk20a *g) |
1614 | { | 1688 | { |
1615 | struct nvhost_gpu_characteristics *gpu = &g->gpu_characteristics; | 1689 | struct nvhost_gpu_characteristics *gpu = &g->gpu_characteristics; |