/*
* Copyright (c) 2011-2019, 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/fb.h>
#include <nvgpu/kmem.h>
#include <nvgpu/nvhost.h>
#include <nvgpu/ptimer.h>
#include <nvgpu/power_features/cg.h>
#include <nvgpu/power_features/pg.h>
#include "os_linux.h"
#include "sysfs.h"
#include "platform_gk20a.h"
#include "gk20a/gr_gk20a.h"
#include "gv11b/gr_gv11b.h"
#define PTIMER_FP_FACTOR 1000000
#define ROOTRW (S_IRWXU|S_IRGRP|S_IROTH)
#define TPC_MASK_FOR_ALL_ACTIVE_TPCs (u32) 0x0
static ssize_t elcg_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct gk20a *g = get_gk20a(dev);
unsigned long val = 0;
int err;
if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL;
err = gk20a_busy(g);
if (err)
return err;
if (val) {
nvgpu_cg_elcg_set_elcg_enabled(g, true);
} else {
nvgpu_cg_elcg_set_elcg_enabled(g, false);
}
gk20a_idle(g);
nvgpu_info(g, "ELCG is %s.", val ? "enabled" :
"disabled");
return count;
}
static ssize_t elcg_enable_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gk20a *g = get_gk20a(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", g->elcg_enabled ? 1 : 0);
}
static DEVICE_ATTR(elcg_enable, ROOTRW, elcg_enable_read, elcg_enable_store);
static ssize_t blcg_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct gk20a *g = get_gk20a(dev);
unsigned long val = 0;
int err;
if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL;
err = gk20a_busy(g);
if (err)
return err;
if (val) {
nvgpu_cg_blcg_set_blcg_enabled(g, true);
} else {
nvgpu_cg_blcg_set_blcg_enabled(g, false);
}
gk20a_idle(g);
nvgpu_info(g, "BLCG is %s.", val ? "enabled" :
"disabled");
return count;
}
static ssize_t blcg_enable_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gk20a *g = get_gk20a(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", g->blcg_enabled ? 1 : 0);
}
static DEVICE_ATTR(blcg_enable, ROOTRW, blcg_enable_read, blcg_enable_store);
static ssize_t slcg_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct gk20a *g = get_gk20a(dev);
unsigned long val = 0;
int err;
if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL;
err = gk20a_busy(g);
if (err) {
return err;
}
if (val) {
nvgpu_cg_slcg_set_slcg_enabled(g, true);
} else {
nvgpu_cg_slcg_set_slcg_enabled(g, false);
}
/*
* TODO: slcg_therm_load_gating is not enabled anywhere during
* init. Therefore, it would be incongruous to add it here. Once
* it is added to init, we should add it here too.
*/
gk20a_idle(g);
nvgpu_info(g, "SLCG is %s.", val ? "enabled" :
"disabled");
return count;
}
static ssize_t slcg_enable_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gk20a *g = get_gk20a(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", g->slcg_enabled ? 1 : 0);
}
static DEVICE_ATTR(slcg_enable, ROOTRW, slcg_enable_read, slcg_enable_store);
static ssize_t ptimer_scale_factor_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct gk20a *g = get_gk20a(dev);
struct gk20a_platform *platform = dev_get_drvdata(dev);
u32 src_freq_hz = platform->ptimer_src_freq;
u32 scaling_factor_fp;
ssize_t res;
if (!src_freq_hz) {
nvgpu_err(g, "reference clk_m rate is not set correctly");
return
|