mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
gpu: nvgpu: ga10b: handling gpcclk requests with GPC floor-swept
ga10b supports floor-sweeping of GPCs. Check for tegra soc fuse info, before making gpcclk requests to BPMP for available GPCs. Bug 3362403 Change-Id: I3f5e2d85b785098ce3a8c8d7d8a5621446e94c15 Signed-off-by: Seshendra Gadagottu <sgadagottu@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2616898 Reviewed-by: Alex Waterman <alexw@nvidia.com> Reviewed-by: Seema Khowala <seemaj@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> GVS: Gerrit_Virtual_Submit Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
f4ec400d5f
commit
a70df981e6
@@ -94,6 +94,19 @@ int nvgpu_tegra_fuse_read_reserved_calib(struct gk20a *g, u32 *val);
|
||||
*/
|
||||
int nvgpu_tegra_fuse_read_gcplex_config_fuse(struct gk20a *g, u32 *val);
|
||||
|
||||
/**
|
||||
* @brief - Reads FUSE_OPT_GPC_DISABLE_0 fuse.
|
||||
*
|
||||
* @param g [in] - GPU super structure.
|
||||
* @param val [out] - Populated with register FUSE_OPT_GPC_DISABLE_0 value.
|
||||
*
|
||||
* - Provide information about the GPU GPC floor-sweep info
|
||||
*
|
||||
* @return 0 on success or negative value on failure.
|
||||
*
|
||||
*/
|
||||
int nvgpu_tegra_fuse_read_opt_gpc_disable(struct gk20a *g, u32 *val);
|
||||
|
||||
/**
|
||||
* @brief - Reads the per-device identifier fuses.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2020-2021, 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,
|
||||
@@ -33,6 +33,10 @@
|
||||
#define FUSE_RESERVED_CALIB0_0 0x204
|
||||
#endif
|
||||
|
||||
#ifndef FUSE_OPT_GPC_DISABLE_0
|
||||
#define FUSE_OPT_GPC_DISABLE_0 0x188
|
||||
#endif
|
||||
|
||||
/* T186+ */
|
||||
#if !defined(FUSE_PDI0) && !defined(FUSE_PDI1)
|
||||
#define FUSE_PDI0 0x300
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2021, 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,
|
||||
@@ -34,6 +34,11 @@ int nvgpu_tegra_fuse_read_gcplex_config_fuse(struct gk20a *g, u32 *val)
|
||||
return tegra_fuse_readl(FUSE_GCPLEX_CONFIG_FUSE_0, val);
|
||||
}
|
||||
|
||||
int nvgpu_tegra_fuse_read_opt_gpc_disable(struct gk20a *g, u32 *val)
|
||||
{
|
||||
return tegra_fuse_readl(FUSE_OPT_GPC_DISABLE_0, val);
|
||||
}
|
||||
|
||||
int nvgpu_tegra_fuse_read_per_device_identifier(struct gk20a *g, u64 *pdi)
|
||||
{
|
||||
u32 lo = 0U;
|
||||
|
||||
@@ -27,10 +27,13 @@
|
||||
#include <linux/platform/tegra/emc_bwmgr.h>
|
||||
#endif
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/fuse.h>
|
||||
|
||||
#include <nvgpu/gk20a.h>
|
||||
#include <nvgpu/nvhost.h>
|
||||
#include <nvgpu/soc.h>
|
||||
#include <nvgpu/fuse.h>
|
||||
#include <nvgpu/linux/soc_fuse.h>
|
||||
|
||||
#ifdef CONFIG_NV_TEGRA_BPMP
|
||||
#include <soc/tegra/tegra-bpmp-dvfs.h>
|
||||
@@ -76,6 +79,34 @@ struct gk20a_platform_clk tegra_ga10b_clocks[] = {
|
||||
{"fuse", UINT_MAX}
|
||||
};
|
||||
|
||||
#define NVGPU_GPC0_DISABLE BIT(0)
|
||||
#define NVGPU_GPC1_DISABLE BIT(1)
|
||||
|
||||
static bool ga10b_tegra_is_clock_available(struct gk20a *g, char *clk_name)
|
||||
{
|
||||
u32 gpc_disable = 0U;
|
||||
|
||||
/* Check for gpc floor-sweeping and report availability of gpcclks */
|
||||
if (nvgpu_tegra_fuse_read_opt_gpc_disable(g, &gpc_disable)) {
|
||||
nvgpu_err(g, "unable to read opt_gpc_disable fuse");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((strcmp(clk_name, "gpc0clk") == 0) &&
|
||||
(gpc_disable & NVGPU_GPC0_DISABLE)) {
|
||||
nvgpu_info(g, "GPC0 is floor-swept");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((strcmp(clk_name, "gpc1clk") == 0) &&
|
||||
(gpc_disable & NVGPU_GPC1_DISABLE)) {
|
||||
nvgpu_info(g, "GPC1 is floor-swept");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function finds clocks in tegra platform and populates
|
||||
* the clock information to platform data.
|
||||
@@ -89,6 +120,7 @@ static int ga10b_tegra_acquire_platform_clocks(struct device *dev,
|
||||
struct gk20a *g = platform->g;
|
||||
struct device_node *np = nvgpu_get_node(g);
|
||||
unsigned int i, num_clks_dt;
|
||||
int err;
|
||||
|
||||
/* Get clocks only on supported platforms(silicon and fpga) */
|
||||
if (!nvgpu_platform_is_silicon(g) && !nvgpu_platform_is_fpga(g)) {
|
||||
@@ -107,15 +139,21 @@ static int ga10b_tegra_acquire_platform_clocks(struct device *dev,
|
||||
|
||||
platform->num_clks = 0;
|
||||
|
||||
/* TODO add floorsweep check before requesting clocks */
|
||||
for (i = 0; i < num_clks_dt; i++) {
|
||||
long rate;
|
||||
struct clk *c = of_clk_get_by_name(np, clk_entries[i].name);
|
||||
struct clk *c;
|
||||
|
||||
if (ga10b_tegra_is_clock_available(g, clk_entries[i].name)) {
|
||||
c = of_clk_get_by_name(np, clk_entries[i].name);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IS_ERR(c)) {
|
||||
nvgpu_info(g, "cannot get clock %s",
|
||||
clk_entries[i].name);
|
||||
/* Continue with other clocks enable */
|
||||
err = PTR_ERR(c);
|
||||
goto err_get_clock;
|
||||
} else {
|
||||
rate = clk_entries[i].default_rate;
|
||||
clk_set_rate(c, rate);
|
||||
@@ -135,6 +173,14 @@ static int ga10b_tegra_acquire_platform_clocks(struct device *dev,
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
err_get_clock:
|
||||
while (i > 0 && i--) {
|
||||
clk_put(platform->clk[i]);
|
||||
platform->clk[i] = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ga10b_tegra_get_clocks(struct device *dev)
|
||||
|
||||
Reference in New Issue
Block a user