gpu: nvgpu: add platform support for Static PG

- Add support for taking static PG config values
  from DT nodes
- Check those values against valid set of values
  for GPC, TPC and FBP
- Store valid values in g->gpc_pg_mask, g->fbp_pg_mask
  and g->tpc_pg_mask[] array.

Bug 200768322
JIRA NVGPU-6433

Change-Id: Ifc87e7d369034b1daa13866bc16a970602514bf6
Signed-off-by: Divya <dsinghatwari@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2594802
Reviewed-by: Vijayakumar Subbu <vsubbu@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-misra <svc-mobile-misra@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@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:
Divya
2021-09-09 07:22:51 +00:00
committed by mobile promotions
parent 9984b59a00
commit ae2d561c48
12 changed files with 364 additions and 113 deletions

View File

@@ -436,7 +436,6 @@ static int nvgpu_init_fbpa_ecc(struct gk20a *g)
static int nvgpu_init_power_gate(struct gk20a *g)
{
int err;
u32 fuse_status = 0x0;
/*
* Pre-Silicon - Static pg feature related settings
@@ -478,12 +477,8 @@ static int nvgpu_init_power_gate(struct gk20a *g)
* halt the GPU poweron.
*/
g->can_tpc_pg = false;
if (g->ops.fuse.fuse_status_opt_tpc_gpc != NULL) {
fuse_status = g->ops.fuse.fuse_status_opt_tpc_gpc(g, 0);
}
if (g->ops.tpc_pg.init_tpc_pg != NULL) {
err = g->ops.tpc_pg.init_tpc_pg(g, fuse_status);
err = g->ops.tpc_pg.init_tpc_pg(g, &g->can_tpc_pg);
if (err != 0) {
return err;
}
@@ -518,7 +513,7 @@ static int nvgpu_init_power_gate_gr(struct gk20a *g)
}
return 0;
}
#endif
#endif /* CONFIG_NVGPU_STATIC_POWERGATE */
static int nvgpu_init_boot_clk_or_clk_arb(struct gk20a *g)
{

View File

@@ -1637,7 +1637,7 @@ static const struct gops_tpc_pg ga10b_ops_tpc_pg = {
* HALs for static-pg will be updated
* for pre-silicon platform during HAL init.
* For silicon, static-pg feature related settings
* will be taken care of by BPMP.
* will be taken care by BPMP.
* Silicon: assigining the HALs to NULL.
* Pre-Silicon: To-do JIRA-NVGPU-7112
* to add these HALs
@@ -1757,8 +1757,8 @@ int ga10b_init_hal(struct gk20a *g)
gops->priv_ring = ga10b_ops_priv_ring;
gops->fuse = ga10b_ops_fuse;
gops->top = ga10b_ops_top;
#ifdef CONFIG_NVGPU_TPC_POWERGATE
gops->tpc = ga10b_ops_tpc;
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
gops->tpc_pg = ga10b_ops_tpc_pg;
#endif
gops->grmgr = ga10b_ops_grmgr;
gops->chip_init_gpu_characteristics = ga10b_init_gpu_characteristics;

View File

@@ -24,32 +24,52 @@
#include <nvgpu/gk20a.h>
#include "tpc_gv11b.h"
int gv11b_tpc_pg(struct gk20a *g, u32 fuse_status)
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
/*
* validate the requested tpc pg mask
* with respect to the current hw value.
*/
int gv11b_tpc_pg(struct gk20a *g, bool *can_tpc_pg)
{
int err = 0;
u32 fuse_status = 0x0;
if (g->ops.fuse.fuse_status_opt_tpc_gpc != NULL) {
fuse_status = g->ops.fuse.fuse_status_opt_tpc_gpc(g, 0);
}
if (fuse_status == 0x0) {
g->can_tpc_pg = true;
/*
* fuse_status = 0x0 means all TPCs are active
* thus, tpc_pg_mask passed by user or DT
* can be applied to powergate the TPC(s).
*/
*can_tpc_pg = true;
} else {
/* if hardware has already floorswept any TPC
* (fuse_status != 0x0) and if TPC PG mask
* sent from userspace is 0x0 GPU will be powered on
* with the default fuse_status setting. It cannot
* un-floorsweep any TPC
* sent from userspace/DT node is 0x0 (it is trying to
* set all TPCs active), GPU will be powered on
* with the default HW fuse_status setting. It cannot
* un-floorsweep any TPC.
* thus, set g->tpc_pg_mask to fuse_status value
* and boot with default HW fuse settings.
*/
if (g->tpc_pg_mask == 0x0) {
g->can_tpc_pg = true;
g->tpc_pg_mask = fuse_status;
if (g->tpc_pg_mask[PG_GPC0] == 0x0U) {
*can_tpc_pg = true;
g->tpc_pg_mask[PG_GPC0] = fuse_status;
} else if (fuse_status == g->tpc_pg_mask) {
g->can_tpc_pg = true;
} else if (fuse_status == g->tpc_pg_mask[PG_GPC0]) {
*can_tpc_pg = true;
} else if ((fuse_status & g->tpc_pg_mask) ==
} else if ((fuse_status & g->tpc_pg_mask[PG_GPC0]) ==
fuse_status) {
g->can_tpc_pg = true;
/*
* if HW has already floorswept any TPC
* check if the tpc_pg_mask sent by user
* is floorsweeping only additional TPCs
*/
*can_tpc_pg = true;
} else {
/* If userspace sends a TPC PG mask such that
* it tries to un-floorsweep any TPC which is
@@ -59,9 +79,9 @@ int gv11b_tpc_pg(struct gk20a *g, u32 fuse_status)
* Return -EINVAL here and halt GPU poweron.
*/
nvgpu_err(g, "Invalid TPC_PG mask: 0x%x",
g->tpc_pg_mask);
g->can_tpc_pg = false;
g->tpc_pg_mask = 0x0;
g->tpc_pg_mask[PG_GPC0]);
*can_tpc_pg = false;
g->tpc_pg_mask[PG_GPC0] = 0x0;
err = -EINVAL;
}
}
@@ -69,19 +89,36 @@ int gv11b_tpc_pg(struct gk20a *g, u32 fuse_status)
return err;
}
/* To-do: check to rename this function */
void gv11b_gr_pg_tpc(struct gk20a *g)
{
u32 tpc_pg_status = g->ops.fuse.fuse_status_opt_tpc_gpc(g, 0);
u32 tpc_pg_status = g->ops.fuse.fuse_status_opt_tpc_gpc(g, PG_GPC0);
if (tpc_pg_status == g->tpc_pg_mask) {
/*
* if the fuse status for tpc is same as tpc_pg_mask
* passed, then do nothing and return
*/
if (tpc_pg_status == g->tpc_pg_mask[PG_GPC0]) {
return;
}
g->ops.fuse.fuse_ctrl_opt_tpc_gpc(g, 0, g->tpc_pg_mask);
/*
* write to fuse_ctrl register to update the fuse settings
* as per the tpc_pg_mask
*/
g->ops.fuse.fuse_ctrl_opt_tpc_gpc(g, PG_GPC0,
g->tpc_pg_mask[PG_GPC0]);
/*
* To confirm that the write was successful
* read the fuse_status register.
* The write done is previous step may take some time to
* get update in fuse_status register
*/
do {
tpc_pg_status = g->ops.fuse.fuse_status_opt_tpc_gpc(g, 0);
} while (tpc_pg_status != g->tpc_pg_mask);
tpc_pg_status = g->ops.fuse.fuse_status_opt_tpc_gpc(g, PG_GPC0);
} while (tpc_pg_status != g->tpc_pg_mask[PG_GPC0]);
return;
}
#endif

View File

@@ -25,10 +25,12 @@
#ifndef NVGPU_TPC_GV11B_H
#define NVGPU_TPC_GV11B_H
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
struct gk20a;
int gv11b_tpc_pg(struct gk20a *g, u32 fuse_status);
int gv11b_tpc_pg(struct gk20a *g, bool *can_tpc_pg);
void gv11b_gr_pg_tpc(struct gk20a *g);
#endif
#endif /* NVGPU_TPC_GV11B_H */

View File

@@ -287,21 +287,24 @@ struct railgate_stats {
/**
* @}
*/
/** @cond DOXYGEN_SHOULD_SKIP_THIS */
/* MAX_TPC_PG_CONFIGS describes the maximum number of
* valid confiurations we can have for the TPC mask. The valid
* mask is used by SW to write to NV_FUSE_OPT_CTRL_GPC_TPC
* register to powergate the TPC in each GPC
*
* MAX_GPC_FBP_FS_CONFIGS describes the maximum number of
* valid confiurations we can have for the GPC and FBP mask.
* The valid mask is used by SW to write to NV_FUSE_OPT_CTRL_GPC
* NV_FUSE_OPT_CTRL_FBP registers to powergate the GPC and
* floorsweep FBP
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
#define MAX_PG_GPC 2
#define MAX_TPC_PER_GPC 4
#define PG_GPC0 0
#define PG_GPC1 1
/*
* MAX_PG_TPC_CONFIGS describes the maximum number of
* valid configurations we can have for the TPC mask.
*/
#define MAX_TPC_PG_CONFIGS 9
#define MAX_GPC_FBP_FS_CONFIGS 3
#define MAX_PG_TPC_CONFIGS (0x1 << MAX_TPC_PER_GPC)
/*
* MAX_PG_GPC_FBP_CONFIGS describes the maximum number of
* valid configurations we can have for the GPC and FBP mask.
*/
#define MAX_PG_GPC_FBP_CONFIGS ((0x1 << MAX_PG_GPC) - 1)
#endif
struct nvgpu_gpfifo_userdata {
struct nvgpu_gpfifo_entry nvgpu_user *entries;
@@ -724,17 +727,25 @@ struct gk20a {
u32 fecs_feature_override_ecc_val;
#endif
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
/** @cond DOXYGEN_SHOULD_SKIP_THIS */
u32 tpc_pg_mask;
/* tpc pg mask array for available GPCs */
u32 tpc_pg_mask[MAX_PG_GPC];
u32 fbp_pg_mask;
u32 gpc_pg_mask;
bool can_tpc_pg;
bool can_fbp_pg;
bool can_gpc_pg;
u32 valid_tpc_mask[MAX_TPC_PG_CONFIGS];
u32 valid_gpc_fbp_fs_mask[MAX_GPC_FBP_FS_CONFIGS];
/*
* Valid config array for tpc pg mask
* and gpc/fbp mask. These valid values
* are chip specific and calculated based
* on available number of GPC, FBP and TPC
*/
u32 valid_tpc_pg_mask[MAX_PG_TPC_CONFIGS];
u32 valid_gpc_fbp_pg_mask[MAX_PG_GPC_FBP_CONFIGS];
#endif
struct nvgpu_bios *bios;
bool bios_is_init;

View File

@@ -24,17 +24,17 @@
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
struct gops_tpc_pg {
int (*init_tpc_pg)(struct gk20a *g, u32 fuse_status);
int (*init_tpc_pg)(struct gk20a *g, bool *can_tpc_pg);
void (*tpc_pg)(struct gk20a *g);
};
struct gops_fbp_pg {
int (*init_fbp_pg)(struct gk20a *g, bool *can_fbp_fs);
int (*init_fbp_pg)(struct gk20a *g, bool *can_fbp_pg);
void (*fbp_pg)(struct gk20a *g);
};
struct gops_gpc_pg {
int (*init_gpc_pg)(struct gk20a *g, bool *can_gpc_fs);
int (*init_gpc_pg)(struct gk20a *g, bool *can_gpc_pg);
void (*gpc_pg)(struct gk20a *g);
};

View File

@@ -184,14 +184,17 @@ static void nvgpu_init_pm_vars(struct gk20a *g)
nvgpu_set_enabled(g, NVGPU_CAN_RAILGATE,
nvgpu_platform_is_simulation(g)? true : platform->can_railgate_init);
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
g->can_tpc_pg = platform->can_tpc_pg;
g->can_gpc_pg = platform->can_gpc_pg;
g->can_fbp_pg = platform->can_fbp_pg;
for (i = 0; i < MAX_TPC_PG_CONFIGS; i++)
g->valid_tpc_mask[i] = platform->valid_tpc_mask[i];
for (i = 0; i < MAX_GPC_FBP_FS_CONFIGS; i++)
g->valid_gpc_fbp_fs_mask[i] = platform->valid_gpc_fbp_fs_mask[i];
for (i = 0; i < MAX_PG_TPC_CONFIGS; i++)
g->valid_tpc_pg_mask[i] = platform->valid_tpc_pg_mask[i];
for (i = 0; i < MAX_PG_GPC_FBP_CONFIGS; i++)
g->valid_gpc_fbp_pg_mask[i] = platform->valid_gpc_fbp_pg_mask[i];
#endif
g->ldiv_slowdown_factor = platform->ldiv_slowdown_factor_init;
/* if default delay is not set, set default delay to 500msec */
if (platform->railgate_delay_init)

View File

@@ -1588,6 +1588,7 @@ static int nvgpu_read_fuse_overrides(struct gk20a *g)
struct gk20a_platform *platform = dev_get_drvdata(dev_from_gk20a(g));
u32 *fuses;
int count, i;
int ret = 0;
if (!np) /* may be pcie device */
return 0;
@@ -1612,24 +1613,44 @@ static int nvgpu_read_fuse_overrides(struct gk20a *g)
case GP10B_FUSE_OPT_ECC_EN:
g->fecs_feature_override_ecc_val = value;
break;
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
case GV11B_FUSE_OPT_TPC_DISABLE:
if (platform->set_tpc_pg_mask != NULL)
platform->set_tpc_pg_mask(dev_from_gk20a(g),
if (platform->set_tpc_pg_mask != NULL) {
ret = platform->set_tpc_pg_mask(dev_from_gk20a(g),
value);
if (ret != 0) {
return -EINVAL;
}
}
break;
case GA10B_FUSE_OPT_TPC_DISABLE:
/* TBD- JIRA NVGPU-6433 */
if (platform->set_tpc_pg_mask != NULL) {
ret = platform->set_tpc_pg_mask(dev_from_gk20a(g),
value);
if (ret != 0) {
return -EINVAL;
}
}
break;
case GA10B_FUSE_OPT_GPC_DISABLE:
if (platform->set_gpc_mask != NULL)
platform->set_gpc_mask(dev_from_gk20a(g),
if (platform->set_gpc_pg_mask != NULL) {
ret = platform->set_gpc_pg_mask(dev_from_gk20a(g),
value);
if (ret != 0) {
return -EINVAL;
}
}
break;
case GA10B_FUSE_OPT_FBP_DISABLE:
if (platform->set_fbp_mask != NULL)
platform->set_fbp_mask(dev_from_gk20a(g),
if (platform->set_fbp_pg_mask != NULL) {
ret = platform->set_fbp_pg_mask(dev_from_gk20a(g),
value);
if (ret != 0) {
return -EINVAL;
}
}
break;
#endif
default:
nvgpu_err(g, "ignore unknown fuse override %08x", fuse);
break;

View File

@@ -281,13 +281,19 @@ static int ga10b_tegra_suspend(struct device *dev)
return 0;
}
static bool is_tpc_mask_valid(struct gk20a_platform *platform, u32 tpc_pg_mask)
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
static bool ga10b_tegra_is_gpc_fbp_pg_mask_valid(struct gk20a_platform *platform,
u32 dt_gpc_fbp_pg_mask)
{
u32 i;
bool valid = false;
for (i = 0; i < MAX_TPC_PG_CONFIGS; i++) {
if (tpc_pg_mask == platform->valid_tpc_mask[i]) {
for (i = 0U; i < MAX_PG_GPC_FBP_CONFIGS; i++) {
/*
* check if gpc/fbp pg mask passed by DT node
* is valid gpc/fbp pg mask
*/
if (dt_gpc_fbp_pg_mask == platform->valid_gpc_fbp_pg_mask[i]) {
valid = true;
break;
}
@@ -295,16 +301,162 @@ static bool is_tpc_mask_valid(struct gk20a_platform *platform, u32 tpc_pg_mask)
return valid;
}
static void ga10b_tegra_set_tpc_pg_mask(struct device *dev, u32 tpc_pg_mask)
static int ga10b_tegra_set_gpc_pg_mask(struct device *dev, u32 dt_gpc_pg_mask)
{
struct gk20a_platform *platform = gk20a_get_platform(dev);
struct gk20a *g = get_gk20a(dev);
if (is_tpc_mask_valid(platform, tpc_pg_mask)) {
g->tpc_pg_mask = tpc_pg_mask;
if (ga10b_tegra_is_gpc_fbp_pg_mask_valid(platform, dt_gpc_pg_mask)) {
g->gpc_pg_mask = dt_gpc_pg_mask;
/*
* update FBP PG mask same as GPC PG mask
* as there is 1:1 mapping for GPC and FBP
*/
g->fbp_pg_mask = dt_gpc_pg_mask;
return 0;
}
nvgpu_err(g, "Invalid GPC-PG mask");
return -EINVAL;
}
static int ga10b_tegra_set_fbp_pg_mask(struct device *dev, u32 dt_fbp_pg_mask)
{
struct gk20a_platform *platform = gk20a_get_platform(dev);
struct gk20a *g = get_gk20a(dev);
if (ga10b_tegra_is_gpc_fbp_pg_mask_valid(platform, dt_fbp_pg_mask)) {
g->fbp_pg_mask = dt_fbp_pg_mask;
/*
* update GPC PG mask same as FBP PG mask
* as there is 1:1 mapping for GPC and FBP
*/
g->gpc_pg_mask = dt_fbp_pg_mask;
return 0;
}
nvgpu_err(g, "Invalid FBP-PG mask");
return -EINVAL;
}
static void ga10b_tegra_set_valid_tpc_pg_mask(struct gk20a_platform *platform)
{
u32 i;
for (i = 0U; i < MAX_PG_TPC_CONFIGS; i++) {
/*
* There are 4 TPCs in each GPC in ga10b
* thus, valid tpc pg mask ranges from
* 0x0 to 0xF
* 0XF will powergate all TPCs, but this
* value will be re-checked again as per the
* the GPC-PG mask
*/
platform->valid_tpc_pg_mask[i] = i;
}
}
static int ga10b_tegra_set_tpc_pg_mask(struct device *dev, u32 dt_tpc_pg_mask)
{
struct gk20a *g = get_gk20a(dev);
struct gk20a_platform *platform = gk20a_get_platform(dev);
u32 i, j;
bool pg_status, valid = false;
/* Hold tpc pg mask value for validation */
u32 tmp_tpc_pg_mask[MAX_PG_GPC];
/* Hold user requested combined tpc pg mask value */
u32 combined_tpc_pg_mask;
/* first set the valid masks ranges for tpc pg */
ga10b_tegra_set_valid_tpc_pg_mask(platform);
/*
* if tpc pg mask sent from DT node tries
* to powergate all the TPCs in both GPC0 and GPC1
* then it is inavlid pg config
*/
if (dt_tpc_pg_mask == 0xFF) {
nvgpu_err(g, "Invalid TPC_PG_MASK:0x%x", dt_tpc_pg_mask);
return -EINVAL;
} else {
/* store dt_tpc_pg_mask in a temp variable */
combined_tpc_pg_mask = dt_tpc_pg_mask;
/* separately store tpc pg mask in a temp array */
for (i = 0U; i < MAX_PG_GPC; i++) {
tmp_tpc_pg_mask[i] = (combined_tpc_pg_mask >> (4*i)) & 0xFU;
}
/* check if the tpc pg mask sent from DT is valid or not */
for (i = 0U ; i < MAX_PG_GPC; i++) {
for (j = 0U; j < MAX_PG_TPC_CONFIGS; j++) {
if (tmp_tpc_pg_mask[i] == platform->valid_tpc_pg_mask[j]) {
/* store the valid config */
g->tpc_pg_mask[i] = tmp_tpc_pg_mask[i];
valid = true;
break;
}
}
if (valid == false) {
nvgpu_err(g, "Invalid TPC PG mask: 0x%x",
tmp_tpc_pg_mask[i]);
return -EINVAL;
}
}
/*
* check if all TPCs of a GPC are powergated
* then powergate the corresponding GPC
*/
for (i = 0U; i < MAX_PG_GPC; i++) {
if (g->tpc_pg_mask[i] == 0xFU) {
g->gpc_pg_mask = (0x1U << i);
g->fbp_pg_mask = (0x1U << i);
}
}
/*
* If any one GPC is already floorswept
* then all the TPCs in that GPC are floorswept
* based on gpc_mask update the tpc_pg_mask
*/
switch (g->gpc_pg_mask) {
case 0x0: /* do nothing as all GPCs are active */
break;
case 0x1:
g->tpc_pg_mask[PG_GPC0] = 0xFU;
break;
case 0x2:
g->tpc_pg_mask[PG_GPC1] = 0xFU;
break;
default:
nvgpu_err(g, "Invalid GPC PG mask: 0x%x",
g->gpc_pg_mask);
return -EINVAL;
}
}
/*
* If both GPC0_TPC and GPC1_TPC mask are 0xF
* then it is invalid as we cannot powergate
* all the TPCs on the chip. This is invalid
* configuration
*/
for (i = 0U; i < MAX_PG_GPC; i++) {
if (g->tpc_pg_mask[i] == 0xF) {
pg_status = true;
} else {
pg_status = false;
break;
}
}
if (pg_status == true) {
nvgpu_err(g, "Disabling all TPCs isn't allowed!");
return -EINVAL;
}
return 0;
}
#endif
struct gk20a_platform ga10b_tegra_platform = {
#ifdef CONFIG_TEGRA_GK20A_NVHOST
.has_syncpoints = true,
@@ -321,11 +473,28 @@ struct gk20a_platform ga10b_tegra_platform = {
.railgate_delay_init = 500,
.can_railgate_init = false,
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
/* add tpc powergate JIRA NVGPU-4683 */
.can_tpc_pg = false,
.can_gpc_pg = false,
.can_fbp_pg = false,
.set_tpc_pg_mask = ga10b_tegra_set_tpc_pg_mask,
/*
* there are 2 GPCs and 2 FBPs
* so the valid config to powergate
* is 0x0 (all active)
* 0x1 (GPC1/FBP1 active)
* 0x2 (GPC0/FBP0 active)
* 0x3 (both powergated) becomes invalid
*/
.valid_gpc_fbp_pg_mask[0] = 0x0,
.valid_gpc_fbp_pg_mask[1] = 0x1,
.valid_gpc_fbp_pg_mask[2] = 0x2,
.set_tpc_pg_mask = ga10b_tegra_set_tpc_pg_mask,
.set_gpc_pg_mask = ga10b_tegra_set_gpc_pg_mask,
.set_fbp_pg_mask = ga10b_tegra_set_fbp_pg_mask,
#endif
.can_slcg = true,
.can_blcg = true,
.can_elcg = true,

View File

@@ -81,6 +81,7 @@ struct gk20a_platform {
/* controls gc off feature for pci gpu */
bool can_pci_gc_off;
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
/* Should be populated at probe. */
bool can_tpc_pg;
@@ -89,7 +90,7 @@ struct gk20a_platform {
/* Should be populated at probe. */
bool can_gpc_pg;
#endif
/* Should be populated at probe. */
bool can_elpg_init;
@@ -118,12 +119,14 @@ struct gk20a_platform {
/* Reset control for device */
struct reset_control *reset_control;
#endif
/* valid TPC-MASK */
u32 valid_tpc_mask[MAX_TPC_PG_CONFIGS];
/* Valid GPC and FBP mask */
u32 valid_gpc_fbp_fs_mask[MAX_GPC_FBP_FS_CONFIGS];
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
/* valid TPC-PG MASK */
u32 valid_tpc_pg_mask[MAX_PG_TPC_CONFIGS];
/* Valid GPC-PG and FBP-PG mask */
u32 valid_gpc_fbp_pg_mask[MAX_PG_GPC_FBP_CONFIGS];
#endif
/* Delay before rail gated */
int railgate_delay_init;
@@ -244,15 +247,16 @@ struct gk20a_platform {
/* Pre callback is called before frequency change */
void (*prescale)(struct device *dev);
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
/* Set TPC_PG_MASK during probe */
void (*set_tpc_pg_mask)(struct device *dev, u32 tpc_pg_mask);
int (*set_tpc_pg_mask)(struct device *dev, u32 dt_tpc_pg_mask);
/* Set GPC_MASK during probe */
void (*set_gpc_mask)(struct device *dev, u32 gpc_mask);
/* Set FBP_MASK during probe */
void (*set_fbp_mask)(struct device *dev, u32 fbp_mask);
/* Set GPC_PG_MASK during probe */
int (*set_gpc_pg_mask)(struct device *dev, u32 dt_gpc_pg_mask);
/* Set FBP_PG_MASK during probe */
int (*set_fbp_pg_mask)(struct device *dev, u32 dt_fbp_pg_mask);
#endif
/* Devfreq governor name. If scaling is enabled, we request
* this governor to be used in scaling */
const char *devfreq_governor;

View File

@@ -207,13 +207,14 @@ static int gv11b_tegra_suspend(struct device *dev)
return 0;
}
static bool is_tpc_mask_valid(struct gk20a_platform *platform, u32 tpc_pg_mask)
static bool gv11b_tegra_is_tpc_mask_valid(struct gk20a_platform *platform,
u32 dt_tpc_pg_mask)
{
u32 i;
bool valid = false;
for (i = 0; i < MAX_TPC_PG_CONFIGS; i++) {
if (tpc_pg_mask == platform->valid_tpc_mask[i]) {
for (i = 0U; i < MAX_PG_TPC_CONFIGS; i++) {
if (dt_tpc_pg_mask == platform->valid_tpc_pg_mask[i]) {
valid = true;
break;
}
@@ -221,13 +222,17 @@ static bool is_tpc_mask_valid(struct gk20a_platform *platform, u32 tpc_pg_mask)
return valid;
}
static void gv11b_tegra_set_tpc_pg_mask(struct device *dev, u32 tpc_pg_mask)
static int gv11b_tegra_set_tpc_pg_mask(struct device *dev, u32 dt_tpc_pg_mask)
{
struct gk20a_platform *platform = gk20a_get_platform(dev);
struct gk20a *g = get_gk20a(dev);
if (is_tpc_mask_valid(platform, tpc_pg_mask)) {
g->tpc_pg_mask = tpc_pg_mask;
if (gv11b_tegra_is_tpc_mask_valid(platform, dt_tpc_pg_mask)) {
g->tpc_pg_mask[PG_GPC0] = dt_tpc_pg_mask;
return 0;
} else {
nvgpu_err(g, "Invalid TPC-PG mask");
return -EINVAL;
}
}
@@ -245,21 +250,22 @@ struct gk20a_platform gv11b_tegra_platform = {
.late_probe = gv11b_tegra_late_probe,
.remove = gv11b_tegra_remove,
.railgate_delay_init = 500,
.can_railgate_init = true,
.can_tpc_pg = true,
.valid_tpc_mask[0] = 0x0,
.valid_tpc_mask[1] = 0x1,
.valid_tpc_mask[2] = 0x2,
.valid_tpc_mask[3] = 0x4,
.valid_tpc_mask[4] = 0x8,
.valid_tpc_mask[5] = 0x5,
.valid_tpc_mask[6] = 0x6,
.valid_tpc_mask[7] = 0x9,
.valid_tpc_mask[8] = 0xa,
.can_railgate_init = true,
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
.can_tpc_pg = true,
.valid_tpc_pg_mask[0] = 0x0,
.valid_tpc_pg_mask[1] = 0x1,
.valid_tpc_pg_mask[2] = 0x2,
.valid_tpc_pg_mask[3] = 0x4,
.valid_tpc_pg_mask[4] = 0x8,
.valid_tpc_pg_mask[5] = 0x5,
.valid_tpc_pg_mask[6] = 0x6,
.valid_tpc_pg_mask[7] = 0x9,
.valid_tpc_pg_mask[8] = 0xa,
.set_tpc_pg_mask = gv11b_tegra_set_tpc_pg_mask,
#endif
.can_slcg = true,
.can_blcg = true,
.can_elcg = true,

View File

@@ -836,14 +836,6 @@ static ssize_t force_idle_read(struct device *dev,
static DEVICE_ATTR(force_idle, ROOTRW, force_idle_read, force_idle_store);
#endif
static ssize_t tpc_pg_mask_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gk20a *g = get_gk20a(dev);
return snprintf(buf, NVGPU_CPU_PAGE_SIZE, "%d\n", g->tpc_pg_mask);
}
static ssize_t gpc_fs_mask_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -886,13 +878,14 @@ static ssize_t fbp_fs_mask_show(struct device *dev,
static DEVICE_ATTR_RO(fbp_fs_mask);
#ifdef CONFIG_NVGPU_STATIC_POWERGATE
static bool is_tpc_mask_valid(struct gk20a *g, u32 tpc_mask)
{
u32 i;
bool valid = false;
for (i = 0; i < MAX_TPC_PG_CONFIGS; i++) {
if (tpc_mask == g->valid_tpc_mask[i]) {
for (i = 0U; i < MAX_PG_TPC_CONFIGS; i++) {
if (tpc_mask == g->valid_tpc_pg_mask[i]) {
valid = true;
break;
}
@@ -900,6 +893,15 @@ static bool is_tpc_mask_valid(struct gk20a *g, u32 tpc_mask)
return valid;
}
static ssize_t tpc_pg_mask_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gk20a *g = get_gk20a(dev);
return snprintf(buf, NVGPU_CPU_PAGE_SIZE, "%d\n",
g->tpc_pg_mask[PG_GPC0]);
}
static ssize_t tpc_pg_mask_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -915,7 +917,7 @@ static ssize_t tpc_pg_mask_store(struct device *dev,
return -EINVAL;
}
if (val == g->tpc_pg_mask) {
if (val == g->tpc_pg_mask[PG_GPC0]) {
nvgpu_info(g, "no value change, same mask already set");
goto exit;
}
@@ -935,7 +937,7 @@ static ssize_t tpc_pg_mask_store(struct device *dev,
* the possible valid TPC configurations.
*/
if (is_tpc_mask_valid(g, (u32)val)) {
g->tpc_pg_mask = val;
g->tpc_pg_mask[PG_GPC0] = val;
} else {
nvgpu_err(g, "TPC-PG mask is invalid");
nvgpu_mutex_release(&g->static_pg_lock);
@@ -946,6 +948,7 @@ exit:
return count;
}
#endif
static DEVICE_ATTR(tpc_pg_mask, ROOTRW, tpc_pg_mask_read, tpc_pg_mask_store);