Files
linux-nvgpu/drivers/gpu/nvgpu/gp10b/platform_gp10b_tegra.c
Mahantesh Kumbar e51dfa9d61 gpu: nvgpu: gp10b: Use clock API to enable clocks
Use CCF to enable GPU clocks. Keep an extra reference to prevent
runtime PM callbacks from disabling clocks while GPU is powered up.

Bug 1673672

Change-Id: I8c34be5ec338fedea62aa3e05bd6bed0513bf1b6
Signed-off-by: Mahantesh Kumbar <mkumbar@nvidia.com>
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/788814
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-on: http://git-master/r/785265
2016-12-27 15:22:07 +05:30

213 lines
5.5 KiB
C

/*
* drivers/video/tegra/host/gk20a/platform_gk20a_tegra.c
*
* GK20A Tegra Platform Interface
*
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/of_platform.h>
#include <linux/nvhost.h>
#include <linux/debugfs.h>
#include <linux/tegra-powergate.h>
#include <linux/platform_data/tegra_edp.h>
#include <uapi/linux/nvgpu.h>
#include <linux/dma-buf.h>
#include <linux/nvmap.h>
#include <linux/tegra_pm_domains.h>
#include "gk20a/platform_gk20a.h"
#include "gk20a/gk20a.h"
#include "platform_tegra.h"
static struct {
char *name;
unsigned long default_rate;
} tegra_gp10b_clocks[] = {
{"gpu", 1900000000},
{"gpu_sys", 204000000} };
/*
* gp10b_tegra_get_clocks()
*
* This function finds clocks in tegra platform and populates
* the clock information to gp10b platform data.
*/
static int gp10b_tegra_get_clocks(struct platform_device *pdev)
{
struct gk20a_platform *platform = platform_get_drvdata(pdev);
struct gk20a *g = get_gk20a(pdev);
struct device *dev = dev_from_gk20a(g);
int i;
if (tegra_platform_is_linsim())
return 0;
platform->num_clks = 0;
for (i = 0; i < ARRAY_SIZE(tegra_gp10b_clocks); i++) {
long rate = tegra_gp10b_clocks[i].default_rate;
struct clk *c;
c = clk_get(dev, tegra_gp10b_clocks[i].name);
if (IS_ERR(c)) {
gk20a_err(&pdev->dev, "cannot get clock %s",
tegra_gp10b_clocks[i].name);
} else {
clk_set_rate(c, rate);
platform->clk[i] = c;
}
}
platform->num_clks = i;
return 0;
}
static int gp10b_tegra_probe(struct platform_device *pdev)
{
struct gk20a_platform *platform = gk20a_get_platform(pdev);
struct device_node *np = pdev->dev.of_node;
struct device_node *host1x_node;
struct platform_device *host1x_pdev;
const __be32 *host1x_ptr;
host1x_ptr = of_get_property(np, "nvidia,host1x", NULL);
if (!host1x_ptr) {
gk20a_err(&pdev->dev, "host1x device not available");
return -ENOSYS;
}
host1x_node = of_find_node_by_phandle(be32_to_cpup(host1x_ptr));
host1x_pdev = of_find_device_by_node(host1x_node);
if (!host1x_pdev) {
gk20a_err(&pdev->dev, "host1x device not available");
return -ENOSYS;
}
platform->g->host1x_dev = host1x_pdev;
platform->bypass_smmu = !device_is_iommuable(&pdev->dev);
platform->disable_bigpage = platform->bypass_smmu;
platform->g->gr.t18x.ctx_vars.dump_ctxsw_stats_on_channel_close
= false;
platform->g->gr.t18x.ctx_vars.dump_ctxsw_stats_on_channel_close
= false;
platform->g->gr.t18x.ctx_vars.force_preemption_gfxp = false;
platform->g->gr.t18x.ctx_vars.force_preemption_cilp = false;
platform->g->gr.t18x.ctx_vars.debugfs_force_preemption_gfxp =
debugfs_create_bool("force_preemption_gfxp", S_IRUGO|S_IWUSR,
platform->debugfs,
&platform->g->gr.t18x.ctx_vars.force_preemption_gfxp);
platform->g->gr.t18x.ctx_vars.debugfs_force_preemption_cilp =
debugfs_create_bool("force_preemption_cilp", S_IRUGO|S_IWUSR,
platform->debugfs,
&platform->g->gr.t18x.ctx_vars.force_preemption_cilp);
platform->g->gr.t18x.ctx_vars.debugfs_dump_ctxsw_stats =
debugfs_create_bool("dump_ctxsw_stats_on_channel_close",
S_IRUGO|S_IWUSR,
platform->debugfs,
&platform->g->gr.t18x.
ctx_vars.dump_ctxsw_stats_on_channel_close);
gp10b_tegra_get_clocks(pdev);
return 0;
}
static int gp10b_tegra_late_probe(struct platform_device *pdev)
{
return 0;
}
static bool gp10b_tegra_is_railgated(struct platform_device *pdev)
{
bool ret = false;
if (!tegra_platform_is_linsim())
ret = !tegra_powergate_is_powered(TEGRA_POWERGATE_GPU);
return ret;
}
static int gp10b_tegra_railgate(struct platform_device *pdev)
{
struct gk20a_platform *platform = gk20a_get_platform(pdev);
if (!tegra_platform_is_linsim() &&
tegra_powergate_is_powered(TEGRA_POWERGATE_GPU)) {
int i;
for (i = 0; i < platform->num_clks; i++) {
if (platform->clk[i])
clk_disable_unprepare(platform->clk[i]);
}
tegra_powergate_partition(TEGRA_POWERGATE_GPU);
}
return 0;
}
static int gp10b_tegra_unrailgate(struct platform_device *pdev)
{
int ret = 0;
struct gk20a_platform *platform = gk20a_get_platform(pdev);
if (!tegra_platform_is_linsim()) {
int i;
ret = tegra_unpowergate_partition(TEGRA_POWERGATE_GPU);
for (i = 0; i < platform->num_clks; i++) {
if (platform->clk[i])
clk_prepare_enable(platform->clk[i]);
}
}
return ret;
}
static int gp10b_tegra_suspend(struct device *dev)
{
return 0;
}
struct gk20a_platform t18x_gpu_tegra_platform = {
.has_syncpoints = true,
/* power management configuration */
.railgate_delay = 500,
.clockgate_delay = 50,
/* power management configuration */
.can_railgate = false,
.enable_elpg = false,
.probe = gp10b_tegra_probe,
.late_probe = gp10b_tegra_late_probe,
/* power management callbacks */
.suspend = gp10b_tegra_suspend,
.railgate = gp10b_tegra_railgate,
.unrailgate = gp10b_tegra_unrailgate,
.is_railgated = gp10b_tegra_is_railgated,
.busy = gk20a_tegra_busy,
.idle = gk20a_tegra_idle,
.dump_platform_dependencies = gk20a_tegra_debug_dump,
.default_big_page_size = SZ_64K,
.has_cde = true,
.secure_alloc = gk20a_tegra_secure_alloc,
.secure_page_alloc = gk20a_tegra_secure_page_alloc,
};