提交 dac55b58 编写于 作者: B Ben Skeggs

drm/nva3/pm: initial pass at set_clock() hook

I still discourage anyone from actually doing this yet.
Signed-off-by: NBen Skeggs <bskeggs@redhat.com>
上级 aa58c405
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -34,8 +34,14 @@
*/
struct nva3_pm_state {
struct pll_lims pll;
int N, M, P;
enum pll_types type;
u32 src0;
u32 src1;
u32 ctrl;
u32 coef;
u32 old_pnm;
u32 new_pnm;
u32 new_div;
};
static int
......@@ -96,36 +102,103 @@ void *
nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
u32 id, int khz)
{
struct nva3_pm_state *state;
int dummy, ret;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return ERR_PTR(-ENOMEM);
struct nva3_pm_state *pll;
struct pll_lims limits;
int N, fN, M, P, diff;
int ret, off;
ret = get_pll_limits(dev, id, &state->pll);
if (ret < 0) {
kfree(state);
ret = get_pll_limits(dev, id, &limits);
if (ret < 0)
return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
off = nva3_pm_pll_offset(id);
if (id < 0)
return ERR_PTR(-EINVAL);
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
pll->type = id;
pll->src0 = 0x004120 + (off * 4);
pll->src1 = 0x004160 + (off * 4);
pll->ctrl = limits.reg + 0;
pll->coef = limits.reg + 4;
/* If target clock is within [-2, 3) MHz of a divisor, we'll
* use that instead of calculating MNP values
*/
pll->new_div = ((limits.refclk * 2) / (khz - 2999)) & 0x0f;
if (pll->new_div) {
diff = khz - ((limits.refclk * 2) / pll->new_div);
if (diff < -2000 || diff >= 3000)
pll->new_div = 0;
}
ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy,
&state->M, &state->P);
if (ret < 0) {
kfree(state);
return ERR_PTR(ret);
if (!pll->new_div) {
ret = nv50_calc_pll2(dev, &limits, khz, &N, &fN, &M, &P);
if (ret < 0)
return ERR_PTR(ret);
pll->new_pnm = (P << 16) | (N << 8) | M;
pll->new_div = 2 - 1;
} else {
pll->new_pnm = 0;
pll->new_div--;
}
return state;
if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101)
pll->old_pnm = nv_rd32(dev, pll->coef);
return pll;
}
void
nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
{
struct nva3_pm_state *state = pre_state;
u32 reg = state->pll.reg;
struct nva3_pm_state *pll = pre_state;
u32 ctrl = 0;
/* For the memory clock, NVIDIA will build a "script" describing
* the reclocking process and ask PDAEMON to execute it.
*/
if (pll->type == PLL_MEMORY) {
nv_wr32(dev, 0x100210, 0);
nv_wr32(dev, 0x1002dc, 1);
nv_wr32(dev, 0x004018, 0x00001000);
ctrl = 0x18000100;
}
if (pll->old_pnm || !pll->new_pnm) {
nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 |
(pll->new_div << 18));
nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
}
if (pll->new_pnm) {
nv_mask(dev, pll->src0, 0x00000101, 0x00000101);
nv_wr32(dev, pll->coef, pll->new_pnm);
nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000);
nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010);
nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl);
nv_mask(dev, pll->src1, 0x00000100, 0x00000000);
nv_mask(dev, pll->src1, 0x00000001, 0x00000000);
if (pll->type == PLL_MEMORY)
nv_wr32(dev, 0x4018, 0x10005000);
} else {
nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
nv_mask(dev, pll->src0, 0x00000100, 0x00000000);
nv_mask(dev, pll->src0, 0x00000001, 0x00000000);
if (pll->type == PLL_MEMORY)
nv_wr32(dev, 0x4018, 0x1000d000);
}
if (pll->type == PLL_MEMORY) {
nv_wr32(dev, 0x1002dc, 0);
nv_wr32(dev, 0x100210, 0x80000000);
}
nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
kfree(state);
kfree(pll);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册