gpu: nvgpu: add debugfs to dump clocks

* Removed unused registers from headers
* Added counter based MCLK
* Removed hardcoding

JIRA DNVGPU-98

Change-Id: Idffcd7fc17024582b41c29371a2295df8f0c206b
Signed-off-by: David Nieto <dmartineznie@nvidia.com>
Reviewed-on: http://git-master/r/1204019
(cherry picked from commit 48dfa41a641c3adbc4d25a35f418cf73b08d5e8c)
Reviewed-on: http://git-master/r/1227264
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
This commit is contained in:
David Nieto
2016-08-08 03:13:37 -07:00
committed by Deepak Nibade
parent 432017248e
commit d2b67f1ad6
5 changed files with 474 additions and 2 deletions

View File

@@ -38,7 +38,8 @@ nvgpu-y += \
$(nvgpu-t18x)/perf/vfe_var.o \
$(nvgpu-t18x)/perf/vfe_equ.o \
$(nvgpu-t18x)/perf/perf.o \
$(nvgpu-t18x)/clk/clk.o
$(nvgpu-t18x)/clk/clk.o \
$(nvgpu-t18x)/gp106/clk_gp106.o
nvgpu-$(CONFIG_TEGRA_GK20A) += $(nvgpu-t18x)/gp10b/platform_gp10b_tegra.o

View File

@@ -0,0 +1,226 @@
/*
* GP106 Clocks
*
* Copyright (c) 2016, 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/clk.h>
#include <linux/delay.h> /* for mdelay */
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/clk/tegra.h>
#include <linux/tegra-fuse.h>
#include "gk20a/gk20a.h"
#include "hw_trim_gp106.h"
#include "clk_gp106.h"
#define gk20a_dbg_clk(fmt, arg...) \
gk20a_dbg(gpu_dbg_clk, fmt, ##arg)
#ifdef CONFIG_DEBUG_FS
static int clk_gp106_debugfs_init(struct gk20a *g);
#endif
#define NUM_NAMEMAPS 4
static int gp106_init_clk_support(struct gk20a *g) {
struct clk_gk20a *clk = &g->clk;
u32 err = 0;
gk20a_dbg_fn("");
mutex_init(&clk->clk_mutex);
clk->clk_namemap = (struct namemap_cfg *)
kzalloc(sizeof(struct namemap_cfg) * NUM_NAMEMAPS, GFP_KERNEL);
if (!clk->clk_namemap)
return -ENOMEM;
clk->clk_namemap[0] = (struct namemap_cfg) {
.namemap = CLK_NAMEMAP_INDEX_GPC2CLK,
.is_enable = 1,
.is_counter = 1,
.g = g,
.cntr.reg_ctrl_addr = trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_r(),
.cntr.reg_ctrl_idx =
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_source_gpc2clk_f(),
.cntr.reg_cntr_addr = trim_gpc_bcast_clk_cntr_ncgpcclk_cnt_r(),
.name = "gpc2clk"
};
clk->clk_namemap[1] = (struct namemap_cfg) {
.namemap = CLK_NAMEMAP_INDEX_SYS2CLK,
.is_enable = 1,
.is_counter = 1,
.g = g,
.cntr.reg_ctrl_addr = trim_sys_clk_cntr_ncsyspll_cfg_r(),
.cntr.reg_ctrl_idx = trim_sys_clk_cntr_ncsyspll_cfg_source_sys2clk_f(),
.cntr.reg_cntr_addr = trim_sys_clk_cntr_ncsyspll_cnt_r(),
.name = "sys2clk"
};
clk->clk_namemap[2] = (struct namemap_cfg) {
.namemap = CLK_NAMEMAP_INDEX_XBAR2CLK,
.is_enable = 1,
.is_counter = 1,
.g = g,
.cntr.reg_ctrl_addr = trim_sys_clk_cntr_ncltcpll_cfg_r(),
.cntr.reg_ctrl_idx = trim_sys_clk_cntr_ncltcpll_cfg_source_xbar2clk_f(),
.cntr.reg_cntr_addr = trim_sys_clk_cntr_ncltcpll_cnt_r(),
.name = "xbar2clk"
};
clk->clk_namemap[3] = (struct namemap_cfg) {
.namemap = CLK_NAMEMAP_INDEX_DRAMCLK,
.is_enable = 1,
.is_counter = 1,
.g = g,
.cntr.reg_ctrl_addr = trim_fbpa_bcast_clk_cntr_ncltcclk_cfg_r(),
.cntr.reg_ctrl_idx =
trim_fbpa_bcast_clk_cntr_ncltcclk_cfg_source_dramdiv4_rec_clk1_f(),
.cntr.reg_cntr_addr = trim_fbpa_bcast_clk_cntr_ncltcclk_cnt_r(),
.name = "dramdiv2_rec_clk1"
};
clk->namemap_num = NUM_NAMEMAPS;
clk->g = g;
#ifdef CONFIG_DEBUG_FS
if (!clk->debugfs_set) {
if (!clk_gp106_debugfs_init(g))
clk->debugfs_set = true;
}
#endif
return err;
}
#ifdef CONFIG_DEBUG_FS
typedef struct namemap_cfg namemap_cfg_t;
static u32 gp106_get_rate_cntr(struct gk20a *, struct namemap_cfg *);
static u32 gp106_get_rate_cntr(struct gk20a *g, struct namemap_cfg *c) {
u32 save_reg;
u32 retries;
u32 cntr = 0;
struct clk_gk20a *clk = &g->clk;
if (!c || !c->cntr.reg_ctrl_addr || !c->cntr.reg_cntr_addr)
return 0;
mutex_lock(&clk->clk_mutex);
/* Save the register */
save_reg = gk20a_readl(g, c->cntr.reg_ctrl_addr);
/* Disable and reset the current clock */
gk20a_writel(g, c->cntr.reg_ctrl_addr,
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_reset_asserted_f() |
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_enable_deasserted_f());
/* Force wb() */
gk20a_readl(g, c->cntr.reg_ctrl_addr);
/* Wait for reset to happen */
retries = CLK_DEFAULT_CNTRL_SETTLE_RETRIES;
do {
udelay(CLK_DEFAULT_CNTRL_SETTLE_USECS);
} while ((--retries) && (cntr = gk20a_readl(g, c->cntr.reg_cntr_addr)));
if (!retries) {
gk20a_err(dev_from_gk20a(g),
"unable to settle counter reset, bailing");
goto read_err;
}
/* Program counter */
gk20a_writel(g, c->cntr.reg_ctrl_addr,
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_reset_deasserted_f() |
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_enable_asserted_f() |
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_write_en_asserted_f() |
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_write_en_asserted_f() |
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_write_en_asserted_f() |
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_noofipclks_f(XTAL_CNTR_CLKS) |
c->cntr.reg_ctrl_idx);
gk20a_readl(g, c->cntr.reg_ctrl_addr);
udelay(XTAL_CNTR_DELAY);
cntr = XTAL_SCALE_TO_KHZ * gk20a_readl(g, c->cntr.reg_cntr_addr);
read_err:
/* reset and restore control register */
gk20a_writel(g, c->cntr.reg_ctrl_addr,
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_reset_asserted_f() |
trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_enable_deasserted_f());
gk20a_readl(g, c->cntr.reg_ctrl_addr);
gk20a_writel(g, c->cntr.reg_ctrl_addr, save_reg);
gk20a_readl(g, c->cntr.reg_ctrl_addr);
mutex_unlock(&clk->clk_mutex);
return cntr;
}
static int gp106_get_rate_show(void *data , u64 *val) {
struct namemap_cfg *c = (struct namemap_cfg *) data;
struct gk20a *g = c->g;
*val = c->is_counter ? gp106_get_rate_cntr(g, c) : 0 /* TODO PLL read */;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(get_rate_fops, gp106_get_rate_show, NULL, "%llu\n");
static int clk_gp106_debugfs_init(struct gk20a *g) {
struct gk20a_platform *platform = dev_get_drvdata(g->dev);
struct dentry *gpu_root = platform->debugfs;
struct dentry *clocks_root;
struct dentry *d;
int i;
if (NULL == (clocks_root = debugfs_create_dir("clocks", gpu_root)))
return -ENOMEM;
gk20a_dbg(gpu_dbg_info, "g=%p", g);
for (i = 0; i < g->clk.namemap_num; i++) {
if (g->clk.clk_namemap[i].is_enable) {
d = debugfs_create_file(
g->clk.clk_namemap[i].name,
S_IRUGO,
clocks_root,
&g->clk.clk_namemap[i],
&get_rate_fops);
if (!d)
goto err_out;
}
}
return 0;
err_out:
pr_err("%s: Failed to make debugfs node\n", __func__);
debugfs_remove_recursive(clocks_root);
return -ENOMEM;
}
#endif /* CONFIG_DEBUG_FS */
void gp106_init_clk_ops(struct gpu_ops *gops) {
gops->clk.init_clk_support = gp106_init_clk_support;
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2016, 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/>.
*/
#ifndef CLK_GP106_H
#define CLK_GP106_H
#include <linux/mutex.h>
#define CLK_NAMEMAP_INDEX_GPC2CLK 0x00
#define CLK_NAMEMAP_INDEX_XBAR2CLK 0x02
#define CLK_NAMEMAP_INDEX_SYS2CLK 0x07 /* SYSPLL */
#define CLK_NAMEMAP_INDEX_DRAMCLK 0x20 /* DRAMPLL */
#define CLK_DEFAULT_CNTRL_SETTLE_RETRIES 10
#define CLK_DEFAULT_CNTRL_SETTLE_USECS 5
#define XTAL_CNTR_CLKS 2700 /* 100usec at 27KHz XTAL */
#define XTAL_CNTR_DELAY 110 /* leave 10 extra usec */
#define XTAL_SCALE_TO_KHZ 10
struct namemap_cfg {
u32 namemap;
u32 is_enable; /* Namemap enabled */
u32 is_counter; /* Using cntr */
struct gk20a *g;
union {
struct {
u32 reg_ctrl_addr;
u32 reg_ctrl_idx;
u32 reg_cntr_addr;
} cntr;
struct {
/* Todo */
} pll;
};
char name[24];
};
void gp106_init_clk_ops(struct gpu_ops *gops);
#endif /* CLK_GP106_H */

View File

@@ -37,7 +37,7 @@
#include "gm20b/gr_gm20b.h"
#include "gm20b/fifo_gm20b.h"
#include "gm20b/pmu_gm20b.h"
#include "gm20b/clk_gm20b.h"
#include "gp106/clk_gp106.h"
#include "gp106/mm_gp106.h"
#include "gp106/pmu_gp106.h"
@@ -156,6 +156,7 @@ int gp106_init_hal(struct gk20a *g)
gp106_init_pmu_ops(gops);
gk20a_init_debug_ops(gops);
gk20a_init_dbg_session_ops(gops);
gp106_init_clk_ops(gops);
gp10b_init_regops(gops);
gp10b_init_cde_ops(gops);
gk20a_init_tsg_ops(gops);

View File

@@ -0,0 +1,189 @@
/*
* Copyright (c) 2016, 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/>.
*/
/*
* Function naming determines intended use:
*
* <x>_r(void) : Returns the offset for register <x>.
*
* <x>_o(void) : Returns the offset for element <x>.
*
* <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
*
* <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
*
* <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
* and masked to place it at field <y> of register <x>. This value
* can be |'d with others to produce a full register value for
* register <x>.
*
* <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
* value can be ~'d and then &'d to clear the value of field <y> for
* register <x>.
*
* <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
* to place it at field <y> of register <x>. This value can be |'d
* with others to produce a full register value for <x>.
*
* <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
* <x> value 'r' after being shifted to place its LSB at bit 0.
* This value is suitable for direct comparison with other unshifted
* values appropriate for use in field <y> of register <x>.
*
* <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
* field <y> of register <x>. This value is suitable for direct
* comparison with unshifted values appropriate for use in field <y>
* of register <x>.
*/
#ifndef _hw_trim_gp106_h_
#define _hw_trim_gp106_h_
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_r(void)
{
return 0x00132924;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_noofipclks_s(void)
{
return 16;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_noofipclks_f(u32 v)
{
return (v & 0xffff) << 0;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_noofipclks_m(void)
{
return 0xffff << 0;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_noofipclks_v(u32 r)
{
return (r >> 0) & 0xffff;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_write_en_s(void)
{
return 1;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_write_en_f(u32 v)
{
return (v & 0x1) << 16;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_write_en_m(void)
{
return 0x1 << 16;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_write_en_v(u32 r)
{
return (r >> 16) & 0x1;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_write_en_deasserted_f(void)
{
return 0;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_write_en_asserted_f(void)
{
return 0x10000;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_enable_s(void)
{
return 1;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_enable_f(u32 v)
{
return (v & 0x1) << 20;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_enable_m(void)
{
return 0x1 << 20;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_enable_v(u32 r)
{
return (r >> 20) & 0x1;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_enable_deasserted_f(void)
{
return 0;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_enable_asserted_f(void)
{
return 0x100000;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_reset_s(void)
{
return 1;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_reset_f(u32 v)
{
return (v & 0x1) << 24;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_reset_m(void)
{
return 0x1 << 24;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_reset_v(u32 r)
{
return (r >> 24) & 0x1;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_reset_deasserted_f(void)
{
return 0;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_reset_asserted_f(void)
{
return 0x1000000;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cfg_source_gpc2clk_f(void)
{
return 0x70000000;
}
static inline u32 trim_gpc_bcast_clk_cntr_ncgpcclk_cnt_r(void)
{
return 0x00132928;
}
static inline u32 trim_fbpa_bcast_clk_cntr_ncltcclk_cfg_r(void)
{
return 0x00132128;
}
static inline u32 trim_fbpa_bcast_clk_cntr_ncltcclk_cfg_source_dramdiv4_rec_clk1_f(void)
{
return 0x20000000;
}
static inline u32 trim_fbpa_bcast_clk_cntr_ncltcclk_cnt_r(void)
{
return 0x0013212c;
}
static inline u32 trim_sys_clk_cntr_ncltcpll_cfg_r(void)
{
return 0x001373c0;
}
static inline u32 trim_sys_clk_cntr_ncltcpll_cfg_source_xbar2clk_f(void)
{
return 0x20000000;
}
static inline u32 trim_sys_clk_cntr_ncltcpll_cnt_r(void)
{
return 0x001373c4;
}
static inline u32 trim_sys_clk_cntr_ncsyspll_cfg_r(void)
{
return 0x001373b0;
}
static inline u32 trim_sys_clk_cntr_ncsyspll_cfg_source_sys2clk_f(void)
{
return 0x0;
}
static inline u32 trim_sys_clk_cntr_ncsyspll_cnt_r(void)
{
return 0x001373b4;
}
#endif