diff options
Diffstat (limited to 'drivers/gpu/nvgpu')
-rw-r--r-- | drivers/gpu/nvgpu/gm20b/clk_gm20b.c | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c index eb8f31e8..aaea080a 100644 --- a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c | |||
@@ -52,7 +52,7 @@ | |||
52 | #define DVFS_SAFE_MARGIN 10 /* 10% */ | 52 | #define DVFS_SAFE_MARGIN 10 /* 10% */ |
53 | static unsigned long dvfs_safe_max_freq; | 53 | static unsigned long dvfs_safe_max_freq; |
54 | 54 | ||
55 | static struct pll_parms gpc_pll_params = { | 55 | static struct pll_parms gpc_pll_params_b1 = { |
56 | 128000, 2600000, /* freq */ | 56 | 128000, 2600000, /* freq */ |
57 | 1300000, 2600000, /* vco */ | 57 | 1300000, 2600000, /* vco */ |
58 | 12000, 38400, /* u */ | 58 | 12000, 38400, /* u */ |
@@ -67,6 +67,23 @@ static struct pll_parms gpc_pll_params = { | |||
67 | 5, /* IDDQ mode exit delay */ | 67 | 5, /* IDDQ mode exit delay */ |
68 | }; | 68 | }; |
69 | 69 | ||
70 | static struct pll_parms gpc_pll_params_c1 = { | ||
71 | 128000, 2600000, /* freq */ | ||
72 | 1300000, 2600000, /* vco */ | ||
73 | 19200, 38400, /* u */ | ||
74 | 1, 255, /* M */ | ||
75 | 8, 255, /* N */ | ||
76 | 1, 31, /* PL */ | ||
77 | 0, 0, /* DFS_COEFF */ | ||
78 | 0, 0, /* ADC char coeff - to be read from fuses */ | ||
79 | 0x7 << 3, /* vco control in NA mode */ | ||
80 | 500, /* Locking and ramping timeout */ | ||
81 | 40, /* Lock delay in NA mode */ | ||
82 | 5, /* IDDQ mode exit delay */ | ||
83 | }; | ||
84 | |||
85 | static struct pll_parms gpc_pll_params; | ||
86 | |||
70 | #ifdef CONFIG_DEBUG_FS | 87 | #ifdef CONFIG_DEBUG_FS |
71 | static int clk_gm20b_debugfs_init(struct gk20a *g); | 88 | static int clk_gm20b_debugfs_init(struct gk20a *g); |
72 | #endif | 89 | #endif |
@@ -110,11 +127,11 @@ static inline u32 div_to_pl(u32 div) | |||
110 | * Post divider tarnsition is glitchless only if there is common "1" in binary | 127 | * Post divider tarnsition is glitchless only if there is common "1" in binary |
111 | * representation of old and new settings. | 128 | * representation of old and new settings. |
112 | */ | 129 | */ |
113 | static u32 get_interim_pldiv(u32 old_pl, u32 new_pl) | 130 | static u32 get_interim_pldiv(struct gk20a *g, u32 old_pl, u32 new_pl) |
114 | { | 131 | { |
115 | u32 pl; | 132 | u32 pl; |
116 | 133 | ||
117 | if (old_pl & new_pl) | 134 | if ((g->clk.gpc_pll.id == GM20B_GPC_PLL_C1) || (old_pl & new_pl)) |
118 | return 0; | 135 | return 0; |
119 | 136 | ||
120 | pl = old_pl | BIT(ffs(new_pl) - 1); /* pl never 0 */ | 137 | pl = old_pl | BIT(ffs(new_pl) - 1); /* pl never 0 */ |
@@ -891,7 +908,7 @@ static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new, | |||
891 | coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r()); | 908 | coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r()); |
892 | if (pldiv_only) { | 909 | if (pldiv_only) { |
893 | /* Insert interim PLDIV state if necessary */ | 910 | /* Insert interim PLDIV state if necessary */ |
894 | u32 interim_pl = get_interim_pldiv(gpll_new->PL, gpll.PL); | 911 | u32 interim_pl = get_interim_pldiv(g, gpll_new->PL, gpll.PL); |
895 | if (interim_pl) { | 912 | if (interim_pl) { |
896 | coeff = set_field(coeff, | 913 | coeff = set_field(coeff, |
897 | trim_sys_gpcpll_coeff_pldiv_m(), | 914 | trim_sys_gpcpll_coeff_pldiv_m(), |
@@ -1135,6 +1152,9 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
1135 | return 0; | 1152 | return 0; |
1136 | } | 1153 | } |
1137 | 1154 | ||
1155 | gpc_pll_params = (clk->gpc_pll.id == GM20B_GPC_PLL_C1) ? | ||
1156 | gpc_pll_params_c1 : gpc_pll_params_b1; | ||
1157 | |||
1138 | if (!gk20a_clk_get(g)) { | 1158 | if (!gk20a_clk_get(g)) { |
1139 | err = -EINVAL; | 1159 | err = -EINVAL; |
1140 | goto fail; | 1160 | goto fail; |
@@ -1159,7 +1179,6 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
1159 | goto fail; | 1179 | goto fail; |
1160 | } | 1180 | } |
1161 | 1181 | ||
1162 | clk->gpc_pll.id = GK20A_GPC_PLL; | ||
1163 | clk->gpc_pll.clk_in = clk_get_rate(ref) / KHZ; | 1182 | clk->gpc_pll.clk_in = clk_get_rate(ref) / KHZ; |
1164 | if (clk->gpc_pll.clk_in == 0) { | 1183 | if (clk->gpc_pll.clk_in == 0) { |
1165 | nvgpu_err(g, "GPCPLL reference clock is zero"); | 1184 | nvgpu_err(g, "GPCPLL reference clock is zero"); |
@@ -1201,9 +1220,11 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
1201 | clk->sw_ready = true; | 1220 | clk->sw_ready = true; |
1202 | 1221 | ||
1203 | gk20a_dbg_fn("done"); | 1222 | gk20a_dbg_fn("done"); |
1204 | dev_info(dev_from_gk20a(g), "GPCPLL initial settings:%s M=%u, N=%u, P=%u", | 1223 | nvgpu_info(g, |
1224 | "GPCPLL initial settings:%s M=%u, N=%u, P=%u (id = %u)", | ||
1205 | clk->gpc_pll.mode == GPC_PLL_MODE_DVFS ? " NA mode," : "", | 1225 | clk->gpc_pll.mode == GPC_PLL_MODE_DVFS ? " NA mode," : "", |
1206 | clk->gpc_pll.M, clk->gpc_pll.N, clk->gpc_pll.PL); | 1226 | clk->gpc_pll.M, clk->gpc_pll.N, clk->gpc_pll.PL, |
1227 | clk->gpc_pll.id); | ||
1207 | return 0; | 1228 | return 0; |
1208 | 1229 | ||
1209 | fail: | 1230 | fail: |
@@ -1623,7 +1644,7 @@ DEFINE_SIMPLE_ATTRIBUTE(rate_fops, rate_get, rate_set, "%llu\n"); | |||
1623 | static int pll_reg_show(struct seq_file *s, void *data) | 1644 | static int pll_reg_show(struct seq_file *s, void *data) |
1624 | { | 1645 | { |
1625 | struct gk20a *g = s->private; | 1646 | struct gk20a *g = s->private; |
1626 | u32 reg, m, n, pl, f; | 1647 | u32 reg, m, n, pl, f, d, dmax, doffs; |
1627 | 1648 | ||
1628 | nvgpu_mutex_acquire(&g->clk.clk_mutex); | 1649 | nvgpu_mutex_acquire(&g->clk.clk_mutex); |
1629 | if (!g->clk.clk_hw_on) { | 1650 | if (!g->clk.clk_hw_on) { |
@@ -1651,6 +1672,12 @@ static int pll_reg_show(struct seq_file *s, void *data) | |||
1651 | f = g->clk.gpc_pll.clk_in * n / (m * pl_to_div(pl)); | 1672 | f = g->clk.gpc_pll.clk_in * n / (m * pl_to_div(pl)); |
1652 | seq_printf(s, "coef = 0x%x : m = %u : n = %u : pl = %u", reg, m, n, pl); | 1673 | seq_printf(s, "coef = 0x%x : m = %u : n = %u : pl = %u", reg, m, n, pl); |
1653 | seq_printf(s, " : pll_f(gpu_f) = %u(%u) kHz\n", f, f/2); | 1674 | seq_printf(s, " : pll_f(gpu_f) = %u(%u) kHz\n", f, f/2); |
1675 | reg = gk20a_readl(g, trim_sys_gpcpll_dvfs0_r()); | ||
1676 | d = trim_sys_gpcpll_dvfs0_dfs_coeff_v(reg); | ||
1677 | dmax = trim_sys_gpcpll_dvfs0_dfs_det_max_v(reg); | ||
1678 | doffs = trim_sys_gpcpll_dvfs0_dfs_dc_offset_v(reg); | ||
1679 | seq_printf(s, "dvfs0 = 0x%x : d = %u : dmax = %u : doffs = %u\n", | ||
1680 | reg, d, dmax, doffs); | ||
1654 | nvgpu_mutex_release(&g->clk.clk_mutex); | 1681 | nvgpu_mutex_release(&g->clk.clk_mutex); |
1655 | return 0; | 1682 | return 0; |
1656 | } | 1683 | } |