Loading drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +46 −27 Original line number Diff line number Diff line Loading @@ -163,17 +163,12 @@ nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) } int nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, nva3_clk_info(struct nouveau_clock *clock, int clk, u32 khz, struct nva3_clock_info *info) { struct nouveau_bios *bios = nouveau_bios(clock); struct nva3_clock_priv *priv = (void *)clock; struct nvbios_pll limits; u32 oclk, sclk, sdiv; int P, N, M, diff; int ret; u32 oclk, sclk, sdiv, diff; info->pll = 0; info->clk = 0; switch (khz) { Loading @@ -188,40 +183,64 @@ nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, return khz; default: sclk = read_vco(priv, clk); sdiv = min((sclk * 2) / (khz - 2999), (u32)65); /* if the clock has a PLL attached, and we can get a within * [-2, 3) MHz of a divider, we'll disable the PLL and use * the divider instead. * * divider can go as low as 2, limited here because NVIDIA sdiv = min((sclk * 2) / khz, (u32)65); oclk = (sclk * 2) / sdiv; diff = ((khz + 3000) - oclk); /* When imprecise, play it safe and aim for a clock lower than * desired rather than higher */ if (diff < 0) { sdiv++; oclk = (sclk * 2) / sdiv; } /* divider can go as low as 2, limited here because NVIDIA * and the VBIOS on my NVA8 seem to prefer using the PLL * for 810MHz - is there a good reason? */ * XXX: PLLs with refclk 810MHz? */ if (sdiv > 4) { oclk = (sclk * 2) / sdiv; diff = khz - oclk; if (!pll || (diff >= -2000 && diff < 3000)) { info->clk = (((sdiv - 2) << 16) | 0x00003100); return oclk; } break; } if (!pll) return -ERANGE; break; } int nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, struct nva3_clock_info *info) { struct nouveau_bios *bios = nouveau_bios(clock); struct nva3_clock_priv *priv = (void *)clock; int clk_khz; struct nvbios_pll limits; int P, N, M, diff; int ret; info->pll = 0; /* If we can get a within [-2, 3) MHz of a divider, we'll disable the * PLL and use the divider instead. */ clk_khz = nva3_clk_info(clock, clk, khz, info); diff = khz - clk_khz; if (!pll || (diff >= -2000 && diff < 3000)) { return clk_khz; } /* Try with PLL */ ret = nvbios_pll_parse(bios, pll, &limits); if (ret) return ret; limits.refclk = read_clk(priv, clk - 0x10, true); if (!limits.refclk) clk_khz = nva3_clk_info(clock, clk - 0x10, limits.refclk, info); if (clk_khz != limits.refclk) return -EINVAL; ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P); if (ret >= 0) { info->clk = nv_rd32(priv, 0x4120 + (clk * 4)); info->pll = (P << 16) | (N << 8) | M; } Loading @@ -232,7 +251,7 @@ static int calc_clk(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate, int clk, u32 pll, int idx) { int ret = nva3_clock_info(&priv->base, clk, pll, cstate->domain[idx], int ret = nva3_pll_info(&priv->base, clk, pll, cstate->domain[idx], &priv->eng[idx]); if (ret >= 0) return 0; Loading @@ -249,7 +268,7 @@ prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx) const u32 coef = pll + 4; if (info->pll) { nv_mask(priv, src0, 0x00000101, 0x00000101); nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk); nv_wr32(priv, coef, info->pll); nv_mask(priv, ctrl, 0x00000015, 0x00000015); nv_mask(priv, ctrl, 0x00000010, 0x00000000); Loading drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h +1 −1 Original line number Diff line number Diff line Loading @@ -8,7 +8,7 @@ struct nva3_clock_info { u32 pll; }; int nva3_clock_info(struct nouveau_clock *, int, u32, u32, int nva3_pll_info(struct nouveau_clock *, int, u32, u32, struct nva3_clock_info *); #endif drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c +1 −1 Original line number Diff line number Diff line Loading @@ -123,7 +123,7 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) timing.data = 0; } ret = nva3_clock_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk); ret = nva3_pll_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk); if (ret < 0) { nv_error(pfb, "failed mclk calculation\n"); return ret; Loading Loading
drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +46 −27 Original line number Diff line number Diff line Loading @@ -163,17 +163,12 @@ nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) } int nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, nva3_clk_info(struct nouveau_clock *clock, int clk, u32 khz, struct nva3_clock_info *info) { struct nouveau_bios *bios = nouveau_bios(clock); struct nva3_clock_priv *priv = (void *)clock; struct nvbios_pll limits; u32 oclk, sclk, sdiv; int P, N, M, diff; int ret; u32 oclk, sclk, sdiv, diff; info->pll = 0; info->clk = 0; switch (khz) { Loading @@ -188,40 +183,64 @@ nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, return khz; default: sclk = read_vco(priv, clk); sdiv = min((sclk * 2) / (khz - 2999), (u32)65); /* if the clock has a PLL attached, and we can get a within * [-2, 3) MHz of a divider, we'll disable the PLL and use * the divider instead. * * divider can go as low as 2, limited here because NVIDIA sdiv = min((sclk * 2) / khz, (u32)65); oclk = (sclk * 2) / sdiv; diff = ((khz + 3000) - oclk); /* When imprecise, play it safe and aim for a clock lower than * desired rather than higher */ if (diff < 0) { sdiv++; oclk = (sclk * 2) / sdiv; } /* divider can go as low as 2, limited here because NVIDIA * and the VBIOS on my NVA8 seem to prefer using the PLL * for 810MHz - is there a good reason? */ * XXX: PLLs with refclk 810MHz? */ if (sdiv > 4) { oclk = (sclk * 2) / sdiv; diff = khz - oclk; if (!pll || (diff >= -2000 && diff < 3000)) { info->clk = (((sdiv - 2) << 16) | 0x00003100); return oclk; } break; } if (!pll) return -ERANGE; break; } int nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, struct nva3_clock_info *info) { struct nouveau_bios *bios = nouveau_bios(clock); struct nva3_clock_priv *priv = (void *)clock; int clk_khz; struct nvbios_pll limits; int P, N, M, diff; int ret; info->pll = 0; /* If we can get a within [-2, 3) MHz of a divider, we'll disable the * PLL and use the divider instead. */ clk_khz = nva3_clk_info(clock, clk, khz, info); diff = khz - clk_khz; if (!pll || (diff >= -2000 && diff < 3000)) { return clk_khz; } /* Try with PLL */ ret = nvbios_pll_parse(bios, pll, &limits); if (ret) return ret; limits.refclk = read_clk(priv, clk - 0x10, true); if (!limits.refclk) clk_khz = nva3_clk_info(clock, clk - 0x10, limits.refclk, info); if (clk_khz != limits.refclk) return -EINVAL; ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P); if (ret >= 0) { info->clk = nv_rd32(priv, 0x4120 + (clk * 4)); info->pll = (P << 16) | (N << 8) | M; } Loading @@ -232,7 +251,7 @@ static int calc_clk(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate, int clk, u32 pll, int idx) { int ret = nva3_clock_info(&priv->base, clk, pll, cstate->domain[idx], int ret = nva3_pll_info(&priv->base, clk, pll, cstate->domain[idx], &priv->eng[idx]); if (ret >= 0) return 0; Loading @@ -249,7 +268,7 @@ prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx) const u32 coef = pll + 4; if (info->pll) { nv_mask(priv, src0, 0x00000101, 0x00000101); nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk); nv_wr32(priv, coef, info->pll); nv_mask(priv, ctrl, 0x00000015, 0x00000015); nv_mask(priv, ctrl, 0x00000010, 0x00000000); Loading
drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h +1 −1 Original line number Diff line number Diff line Loading @@ -8,7 +8,7 @@ struct nva3_clock_info { u32 pll; }; int nva3_clock_info(struct nouveau_clock *, int, u32, u32, int nva3_pll_info(struct nouveau_clock *, int, u32, u32, struct nva3_clock_info *); #endif
drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c +1 −1 Original line number Diff line number Diff line Loading @@ -123,7 +123,7 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) timing.data = 0; } ret = nva3_clock_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk); ret = nva3_pll_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk); if (ret < 0) { nv_error(pfb, "failed mclk calculation\n"); return ret; Loading