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:
Seshendra Gadagottu
2021-10-26 08:41:50 -07:00
committed by mobile promotions
parent f4ec400d5f
commit a70df981e6
4 changed files with 73 additions and 5 deletions

View File

@@ -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); 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. * @brief - Reads the per-device identifier fuses.
* *

View File

@@ -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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -33,6 +33,10 @@
#define FUSE_RESERVED_CALIB0_0 0x204 #define FUSE_RESERVED_CALIB0_0 0x204
#endif #endif
#ifndef FUSE_OPT_GPC_DISABLE_0
#define FUSE_OPT_GPC_DISABLE_0 0x188
#endif
/* T186+ */ /* T186+ */
#if !defined(FUSE_PDI0) && !defined(FUSE_PDI1) #if !defined(FUSE_PDI0) && !defined(FUSE_PDI1)
#define FUSE_PDI0 0x300 #define FUSE_PDI0 0x300

View File

@@ -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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * 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); 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) int nvgpu_tegra_fuse_read_per_device_identifier(struct gk20a *g, u64 *pdi)
{ {
u32 lo = 0U; u32 lo = 0U;

View File

@@ -27,10 +27,13 @@
#include <linux/platform/tegra/emc_bwmgr.h> #include <linux/platform/tegra/emc_bwmgr.h>
#endif #endif
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/fuse.h>
#include <nvgpu/gk20a.h> #include <nvgpu/gk20a.h>
#include <nvgpu/nvhost.h> #include <nvgpu/nvhost.h>
#include <nvgpu/soc.h> #include <nvgpu/soc.h>
#include <nvgpu/fuse.h>
#include <nvgpu/linux/soc_fuse.h>
#ifdef CONFIG_NV_TEGRA_BPMP #ifdef CONFIG_NV_TEGRA_BPMP
#include <soc/tegra/tegra-bpmp-dvfs.h> #include <soc/tegra/tegra-bpmp-dvfs.h>
@@ -76,6 +79,34 @@ struct gk20a_platform_clk tegra_ga10b_clocks[] = {
{"fuse", UINT_MAX} {"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 * This function finds clocks in tegra platform and populates
* the clock information to platform data. * 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 gk20a *g = platform->g;
struct device_node *np = nvgpu_get_node(g); struct device_node *np = nvgpu_get_node(g);
unsigned int i, num_clks_dt; unsigned int i, num_clks_dt;
int err;
/* Get clocks only on supported platforms(silicon and fpga) */ /* Get clocks only on supported platforms(silicon and fpga) */
if (!nvgpu_platform_is_silicon(g) && !nvgpu_platform_is_fpga(g)) { 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; platform->num_clks = 0;
/* TODO add floorsweep check before requesting clocks */
for (i = 0; i < num_clks_dt; i++) { for (i = 0; i < num_clks_dt; i++) {
long rate; 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)) { if (IS_ERR(c)) {
nvgpu_info(g, "cannot get clock %s", nvgpu_info(g, "cannot get clock %s",
clk_entries[i].name); clk_entries[i].name);
/* Continue with other clocks enable */ err = PTR_ERR(c);
goto err_get_clock;
} else { } else {
rate = clk_entries[i].default_rate; rate = clk_entries[i].default_rate;
clk_set_rate(c, rate); clk_set_rate(c, rate);
@@ -135,6 +173,14 @@ static int ga10b_tegra_acquire_platform_clocks(struct device *dev,
#endif #endif
return 0; 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) static int ga10b_tegra_get_clocks(struct device *dev)