diff --git a/drivers/gpu/nvgpu/common/pmu/clk/clk_fll.c b/drivers/gpu/nvgpu/common/pmu/clk/clk_fll.c index 6d1e483f6..7828f559c 100644 --- a/drivers/gpu/nvgpu/common/pmu/clk/clk_fll.c +++ b/drivers/gpu/nvgpu/common/pmu/clk/clk_fll.c @@ -273,6 +273,8 @@ static int devinit_get_fll_device_table(struct gk20a *g, if (desctablesize >= FLL_DESCRIPTOR_HEADER_10_SIZE_6) { pfllobjs->max_min_freq_mhz = fll_desc_table_header.max_min_freq_mhz; + pfllobjs->freq_margin_vfe_idx = + fll_desc_table_header.freq_margin_vfe_idx; } else { pfllobjs->max_min_freq_mhz = 0; } diff --git a/drivers/gpu/nvgpu/common/pmu/clk/clk_vf_point.c b/drivers/gpu/nvgpu/common/pmu/clk/clk_vf_point.c index 8bf8f3cdd..06dedc6bd 100644 --- a/drivers/gpu/nvgpu/common/pmu/clk/clk_vf_point.c +++ b/drivers/gpu/nvgpu/common/pmu/clk/clk_vf_point.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "clk.h" #include "clk_vf_point.h" @@ -475,7 +476,7 @@ int nvgpu_clk_set_req_fll_clk_ps35(struct gk20a *g, struct nvgpu_clk_slave_freq u32 max_clkmhz; u16 max_ratio; struct clk_set_info *p0_info; - u32 vmin_uv = 0; + u32 vmin_uv = 0, vmargin_uv = 0U, fmargin_mhz = 0U; (void) memset(&change_input, 0, sizeof(struct ctrl_perf_change_seq_change_input)); @@ -604,9 +605,23 @@ int nvgpu_clk_set_req_fll_clk_ps35(struct gk20a *g, struct nvgpu_clk_slave_freq change_input.flags = (u32)CTRL_PERF_CHANGE_SEQ_CHANGE_FORCE; change_input.vf_points_cache_counter = 0xFFFFFFFFU; + status = nvgpu_vfe_get_freq_margin_limit(g, &fmargin_mhz); + if (status != 0) { + nvgpu_err(g, "Failed to fetch Fmargin status=0x%x", status); + return status; + } + + gpcclk_clkmhz += fmargin_mhz; status = clk_domain_freq_to_volt(g, gpcclk_domain, &gpcclk_clkmhz, &gpcclk_voltuv, CTRL_VOLT_DOMAIN_LOGIC); + status = nvgpu_vfe_get_volt_margin_limit(g, &vmargin_uv); + if (status != 0) { + nvgpu_err(g, "Failed to fetch Vmargin status=0x%x", status); + return status; + } + + gpcclk_voltuv += vmargin_uv; status = g->ops.pmu_ver.volt.volt_get_vmin(g, &vmin_uv); if (status != 0) { nvgpu_err(g, "Failed to execute Vmin get_status status=0x%x", diff --git a/drivers/gpu/nvgpu/common/pmu/perf/vfe_equ.c b/drivers/gpu/nvgpu/common/pmu/perf/vfe_equ.c index 0505d0fca..d57b0d2cc 100644 --- a/drivers/gpu/nvgpu/common/pmu/perf/vfe_equ.c +++ b/drivers/gpu/nvgpu/common/pmu/perf/vfe_equ.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "pmu_perf.h" #include "vfe_equ.h" @@ -738,3 +739,60 @@ static struct vfe_equ *construct_vfe_equ(struct gk20a *g, void *pargs) return (struct vfe_equ *)board_obj_ptr; } + +int nvgpu_vfe_get_volt_margin_limit(struct gk20a *g, u32 *vmargin_uv) +{ + struct nvgpu_pmu *pmu = &g->pmu; + struct nv_pmu_rpc_struct_perf_vfe_eval rpc; + int status = 0; + u8 vmargin_idx; + + vmargin_idx = g->ops.pmu_ver.volt.volt_get_vmargin(g); + if (vmargin_idx == 0U) { + nvgpu_info(g, "Skipping volt margin idx"); + return 0; + } + + (void) memset(&rpc, 0, sizeof(rpc)); + rpc.data.equ_idx = vmargin_idx; + rpc.data.output_type = CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_DELTA_UV; + rpc.data.var_count = 0U; + PMU_RPC_EXECUTE_CPB(status, pmu, PERF, VFE_EQU_EVAL, &rpc, 0); + if (status != 0) { + nvgpu_err(g, "Failed to execute RPC status=0x%x", + status); + return status; + } + + *vmargin_uv = rpc.data.result.voltu_v; + return status; +} + +int nvgpu_vfe_get_freq_margin_limit(struct gk20a *g, u32 *fmargin_mhz) +{ + struct nvgpu_pmu *pmu = &g->pmu; + struct nv_pmu_rpc_struct_perf_vfe_eval rpc; + int status = 0; + u8 fmargin_idx; + struct nvgpu_avfsfllobjs *pfllobjs = &(g->clk_pmu->avfs_fllobjs); + + fmargin_idx = pfllobjs->freq_margin_vfe_idx; + if (fmargin_idx == 255U) { + nvgpu_info(g, "Skipping freq margin idx"); + return 0; + } + + (void) memset(&rpc, 0, sizeof(rpc)); + rpc.data.equ_idx = fmargin_idx; + rpc.data.output_type = CTRL_PERF_VFE_EQU_OUTPUT_TYPE_FREQ_MHZ; + rpc.data.var_count = 0U; + PMU_RPC_EXECUTE_CPB(status, pmu, PERF, VFE_EQU_EVAL, &rpc, 0); + if (status != 0) { + nvgpu_err(g, "Failed to execute RPC status=0x%x", + status); + return status; + } + + *fmargin_mhz = rpc.data.result.voltu_v; + return status; +} diff --git a/drivers/gpu/nvgpu/common/pmu/pmu_fw.c b/drivers/gpu/nvgpu/common/pmu/pmu_fw.c index 477e62edb..5ca174c6a 100644 --- a/drivers/gpu/nvgpu/common/pmu/pmu_fw.c +++ b/drivers/gpu/nvgpu/common/pmu/pmu_fw.c @@ -1333,6 +1333,8 @@ static int init_pmu_fw_ver_ops(struct nvgpu_pmu *pmu, u32 app_version) g->ops.pmu_ver.clk.clk_set_boot_clk = NULL; g->ops.pmu_ver.volt.volt_get_vmin = nvgpu_volt_get_vmin_tu10x; + g->ops.pmu_ver.volt.volt_get_vmargin = + nvgpu_volt_get_vmargin_tu10x; } } else { g->ops.pmu_ver.get_pmu_init_msg_pmu_queue_params = diff --git a/drivers/gpu/nvgpu/common/pmu/volt/volt_pmu.c b/drivers/gpu/nvgpu/common/pmu/volt/volt_pmu.c index 80df27dba..d679d81f2 100644 --- a/drivers/gpu/nvgpu/common/pmu/volt/volt_pmu.c +++ b/drivers/gpu/nvgpu/common/pmu/volt/volt_pmu.c @@ -413,3 +413,21 @@ int nvgpu_volt_get_vmin_tu10x(struct gk20a *g, u32 *vmin_uv) return status; } +u8 nvgpu_volt_get_vmargin_tu10x(struct gk20a *g) +{ + struct boardobjgrp *pboardobjgrp; + struct boardobj *pboardobj = NULL; + struct voltage_rail *volt_rail = NULL; + u8 index, vmargin_uv; + + pboardobjgrp = &g->perf_pmu->volt.volt_rail_metadata.volt_rails.super; + + BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct boardobj *, pboardobj, index) { + volt_rail = (struct voltage_rail *)(void *)pboardobj; + if (volt_rail->volt_margin_limit_vfe_equ_idx != 255U) { + vmargin_uv = volt_rail->volt_margin_limit_vfe_equ_idx; + return vmargin_uv; + } + } + return 0U; +} diff --git a/drivers/gpu/nvgpu/include/nvgpu/bios.h b/drivers/gpu/nvgpu/include/nvgpu/bios.h index 389647b03..94c776f23 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/bios.h +++ b/drivers/gpu/nvgpu/include/nvgpu/bios.h @@ -98,6 +98,7 @@ struct fll_descriptor_header_10 { u8 entry_size; u8 entry_count; u16 max_min_freq_mhz; + u8 freq_margin_vfe_idx; } __packed; #define FLL_DESCRIPTOR_ENTRY_10_SIZE 15U diff --git a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h index cc809274f..7054ea75b 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h +++ b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h @@ -1045,6 +1045,7 @@ struct gpu_ops { u8 volt_domain, u32 *pvoltage_uv); int (*volt_send_load_cmd_to_pmu)(struct gk20a *g); int (*volt_get_vmin)(struct gk20a *g, u32 *vmin_uv); + u8 (*volt_get_vmargin)(struct gk20a *g); } volt; struct { u32 (*get_vbios_clk_domain)(u32 vbios_domain); diff --git a/drivers/gpu/nvgpu/include/nvgpu/pmu/clk/clk_fll.h b/drivers/gpu/nvgpu/include/nvgpu/pmu/clk/clk_fll.h index 2407b881d..28601813e 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/pmu/clk/clk_fll.h +++ b/drivers/gpu/nvgpu/include/nvgpu/pmu/clk/clk_fll.h @@ -38,6 +38,7 @@ struct nvgpu_avfsfllobjs { u32 lut_min_voltage_uv; u8 lut_num_entries; u16 max_min_freq_mhz; + u8 freq_margin_vfe_idx; }; struct nvgpu_set_fll_clk { diff --git a/drivers/gpu/nvgpu/include/nvgpu/pmu/perf.h b/drivers/gpu/nvgpu/include/nvgpu/pmu/perf.h index 537fb2936..1af51d656 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/pmu/perf.h +++ b/drivers/gpu/nvgpu/include/nvgpu/pmu/perf.h @@ -99,6 +99,8 @@ int vfe_equ_pmu_setup(struct gk20a *g); int vfe_var_sw_setup(struct gk20a *g); int vfe_var_pmu_setup(struct gk20a *g); +int nvgpu_vfe_get_volt_margin_limit(struct gk20a *g, u32 *vmargin_uv); +int nvgpu_vfe_get_freq_margin_limit(struct gk20a *g, u32 *fmargin_mhz); int nvgpu_perf_change_seq_sw_setup(struct gk20a *g); int nvgpu_perf_change_seq_pmu_setup(struct gk20a *g); diff --git a/drivers/gpu/nvgpu/include/nvgpu/pmu/volt.h b/drivers/gpu/nvgpu/include/nvgpu/pmu/volt.h index 93ccb0035..6343e2689 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/pmu/volt.h +++ b/drivers/gpu/nvgpu/include/nvgpu/pmu/volt.h @@ -82,5 +82,6 @@ int volt_policy_sw_setup(struct gk20a *g); int volt_policy_pmu_setup(struct gk20a *g); int nvgpu_volt_rail_boardobj_grp_get_status(struct gk20a *g); int nvgpu_volt_get_vmin_tu10x(struct gk20a *g, u32 *vmin_uv); +u8 nvgpu_volt_get_vmargin_tu10x(struct gk20a *g); #endif /* NVGPU_PMU_VOLT_H */ diff --git a/drivers/gpu/nvgpu/include/nvgpu/pmuif/gpmuifperf.h b/drivers/gpu/nvgpu/include/nvgpu/pmuif/gpmuifperf.h index f7fe176e4..589835e62 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/pmuif/gpmuifperf.h +++ b/drivers/gpu/nvgpu/include/nvgpu/pmuif/gpmuifperf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2019, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -59,7 +59,7 @@ * used to execute LOAD RPC. */ struct nv_pmu_rpc_struct_perf_load { - /*[IN/OUT] Must be first field in RPC structure */ + /* [IN/OUT] Must be first field in RPC structure */ struct nv_pmu_rpc_header hdr; bool b_load; u32 scratch[1]; @@ -215,4 +215,11 @@ struct perf_change_seq_pmu_script { steps[CTRL_PERF_CHANGE_SEQ_PMU_STEP_ID_MAX_STEPS]; }; +struct nv_pmu_rpc_struct_perf_vfe_eval { + /*[IN/OUT] Must be first field in RPC structure */ + struct nv_pmu_rpc_header hdr; + struct nv_pmu_perf_rpc_vfe_equ_eval data; + u32 scratch[1]; +}; + #endif /* NVGPU_PMUIF_GPMUIFPERF_H*/