[Nouveau] [PATCH] pll/gk104: fix PLL instability due to bad configuration with gddr5
Ben Skeggs
skeggsb at gmail.com
Tue Oct 13 15:53:47 PDT 2015
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
On 10/13/2015 06:18 AM, Karol Herbst wrote:
> this patch uses an approach closer to the nvidia driver to
> configure both PLLs for high gddr5 memory clocks (usually above
> 2400MHz)
>
> previously nouveau used the one PLL as it was used for the lower
> clocks and just adjusted the second PLL to get as close as possible
> to the requested clock. This means for my card, that I got a 4050
> MHz clock allthough 4008 MHz was requested.
>
> now the driver iterates over a list of PLL configuration also used
> by the nvidia driver and then adjust the second PLL to get near
> the requested clock. Also it hold to some restriction I found while
> analyzing the PLL configurations
>
> This won't fix all gddr5 high clock issues itself, but it should be
> fine on hybrid gpu systems as found on many laptops these days.
> Also switching while normal desktop usage should be a lot more
> stable than before.
Given that we really have no better ideas right now, I think the patch
is basically fine.
I think though, that given these PLLs are limited to FB, that you may
as well just stick the code in subdev/fb/ramgk104.c and be done with
it, there's no need for it to live in subdev/clk at all.
Ben.
>
> Signed-off-by: Karol Herbst <nouveau at karolherbst.de> ---
> drm/nouveau/nvkm/subdev/clk/Kbuild | 1 +
> drm/nouveau/nvkm/subdev/clk/pll.h | 5 +++
> drm/nouveau/nvkm/subdev/clk/pllgk104.c | 77
> ++++++++++++++++++++++++++++++++++
> drm/nouveau/nvkm/subdev/clk/pllgt215.c | 6 +++
> drm/nouveau/nvkm/subdev/fb/ramgk104.c | 39 +++++++---------- 5
> files changed, 105 insertions(+), 23 deletions(-) create mode
> 100644 drm/nouveau/nvkm/subdev/clk/pllgk104.c
>
> diff --git a/drm/nouveau/nvkm/subdev/clk/Kbuild
> b/drm/nouveau/nvkm/subdev/clk/Kbuild index ed7717b..5ac23fe 100644
> --- a/drm/nouveau/nvkm/subdev/clk/Kbuild +++
> b/drm/nouveau/nvkm/subdev/clk/Kbuild @@ -11,3 +11,4 @@ nvkm-y +=
> nvkm/subdev/clk/gk20a.o
>
> nvkm-y += nvkm/subdev/clk/pllnv04.o nvkm-y +=
> nvkm/subdev/clk/pllgt215.o +nvkm-y += nvkm/subdev/clk/pllgk104.o
> diff --git a/drm/nouveau/nvkm/subdev/clk/pll.h
> b/drm/nouveau/nvkm/subdev/clk/pll.h index 44020a3..1f5e0a0 100644
> --- a/drm/nouveau/nvkm/subdev/clk/pll.h +++
> b/drm/nouveau/nvkm/subdev/clk/pll.h @@ -4,8 +4,13 @@ struct
> nvkm_subdev; struct nvbios_pll;
>
> +int calc_pll_clock(int fN, int M, int N, int P, int clk); + int
> nv04_pll_calc(struct nvkm_subdev *, struct nvbios_pll *, u32 freq,
> int *N1, int *M1, int *N2, int *M2, int *P); int
> gt215_pll_calc(struct nvkm_subdev *, struct nvbios_pll *, u32
> freq, int *N, int *fN, int *M, int *P); +int
> gk104_pll_calc_hiclk(int target_khz, int crystal, + int *N1, int
> *fN1, int *M1, int *P1, + int *N2, int *M2, int *P2); #endif diff
> --git a/drm/nouveau/nvkm/subdev/clk/pllgk104.c
> b/drm/nouveau/nvkm/subdev/clk/pllgk104.c new file mode 100644 index
> 0000000..4863e64 --- /dev/null +++
> b/drm/nouveau/nvkm/subdev/clk/pllgk104.c @@ -0,0 +1,77 @@ +/* + *
> Copyright 2015 Karol Herbst + * + * Permission is hereby granted,
> free of charge, to any person obtaining a + * copy of this software
> and associated documentation files (the "Software"), + * to deal in
> the Software without restriction, including without limitation + *
> the rights to use, copy, modify, merge, publish, distribute,
> sublicense, + * and/or sell copies of the Software, and to permit
> persons to whom the + * Software is furnished to do so, subject to
> the following conditions: + * + * The above copyright notice and
> this permission notice shall be included in + * all copies or
> substantial portions of the Software. + * + * THE SOFTWARE IS
> PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + *
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND
> NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR
> AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY,
> WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING
> FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + *
> OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Karol Herbst + */
> +#include "pll.h" + +int +gk104_pll_calc_hiclk(int target_khz, int
> crystal, + int *N1, int *fN1, int *M1, int *P1, + int *N2, int
> *M2, int *P2) +{ + int best_clk = 0, best_err = target_khz, p_ref,
> n_ref; + bool upper = false; + + *M1 = 1; + /* M has to be 1,
> otherwise it gets unstable */ + *M2 = 1; + /* can be 1 or 2,
> sticking with 1 for simplicity */ + *P2 = 1; + + for (p_ref = 0x7;
> p_ref >= 0x5; --p_ref) { + for (n_ref = 0x25; n_ref <= 0x2b;
> ++n_ref) { + int cur_N, cur_clk, cur_err; + + cur_clk =
> calc_pll_clock(0, 1, n_ref, p_ref, crystal); + cur_N = target_khz
> / cur_clk; + cur_err = target_khz - calc_pll_clock(0xf000, 1,
> cur_N, 1, cur_clk); + + /* we found a better combination */ + if
> (cur_err < best_err) { + best_err = cur_err; + best_clk =
> cur_clk; + *N2 = cur_N; + *N1 = n_ref; + *P1 = p_ref; +
> upper = false; + } + + cur_N += 1; + cur_err =
> calc_pll_clock(0xf000, 1, cur_N, 1, cur_clk) - target_khz; + if
> (cur_err < best_err) { + best_err = cur_err; + best_clk =
> cur_clk; + *N2 = cur_N; + *N1 = n_ref; + *P1 = p_ref; + upper
> = true; + } + } + } + + /* adjust fN to get closer to the target
> clock */ + *fN1 = (u16)((((best_err / *N2 * *P2) * (*P1 * *M1)) <<
> 13) / crystal); + if (upper) + *fN1 = (u16)(1 - *fN1); + + return
> calc_pll_clock(*fN1, 1, *N1, *P1, crystal); +} diff --git
> a/drm/nouveau/nvkm/subdev/clk/pllgt215.c
> b/drm/nouveau/nvkm/subdev/clk/pllgt215.c index c6fccd6..fe9886c
> 100644 --- a/drm/nouveau/nvkm/subdev/clk/pllgt215.c +++
> b/drm/nouveau/nvkm/subdev/clk/pllgt215.c @@ -27,6 +27,12 @@
> #include <subdev/bios/pll.h>
>
> int +calc_pll_clock(int fN, int M, int N, int P, int clk) +{ +
> return ((clk * N) + (((u16)(fN + 4096) * clk) >> 13)) / (M * P);
> +} + +int gt215_pll_calc(struct nvkm_subdev *subdev, struct
> nvbios_pll *info, u32 freq, int *pN, int *pfN, int *pM, int *P) {
> diff --git a/drm/nouveau/nvkm/subdev/fb/ramgk104.c
> b/drm/nouveau/nvkm/subdev/fb/ramgk104.c index 9893556..c4373bf
> 100644 --- a/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++
> b/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -968,31 +968,24 @@
> gk104_ram_calc_xits(struct gk104_ram *ram, struct nvkm_ram_data
> *next) * kepler boards, no idea how/why they're chosen. */ refclk =
> next->freq; - if (ram->mode == 2) - refclk = fuc->mempll.refclk; -
> - /* calculate refpll coefficients */ - ret =
> gt215_pll_calc(subdev, &fuc->refpll, refclk, &ram->N1, -
> &ram->fN1, &ram->M1, &ram->P1); - fuc->mempll.refclk = ret; - if
> (ret <= 0) { - nvkm_error(subdev, "unable to calc refpll\n"); -
> return -EINVAL; - } - - /* calculate mempll coefficients, if we're
> using it */ if (ram->mode == 2) { - /* post-divider doesn't
> work... the reg takes the values but - * appears to completely
> ignore it. there *is* a bit at - * bit 28 that appears to divide
> the clock by 2 if set. - */ - fuc->mempll.min_p = 1; -
> fuc->mempll.max_p = 2; - - ret = gt215_pll_calc(subdev,
> &fuc->mempll, next->freq, - &ram->N2, NULL, &ram->M2, &ram->P2); +
> ret = gk104_pll_calc_hiclk(next->freq, subdev->device->crystal, +
> &ram->N1, &ram->fN1, &ram->M1, &ram->P1, + &ram->N2, &ram->M2,
> &ram->P2); + fuc->mempll.refclk = ret; + if (ret <= 0) { +
> nvkm_error(subdev, "unable to calc plls\n"); + return -EINVAL; +
> } + nvkm_debug(subdev, "sucessfully calced PLLs for clock %i kHz"
> + " (refclock: %i kHz)\n", next->freq, ret); + } else { + /*
> calculate refpll coefficients */ + ret = gt215_pll_calc(subdev,
> &fuc->refpll, refclk, &ram->N1, + &ram->fN1, &ram->M1,
> &ram->P1); + fuc->mempll.refclk = ret; if (ret <= 0) { -
> nvkm_error(subdev, "unable to calc mempll\n"); + nvkm_error(subdev,
> "unable to calc refpll\n"); return -EINVAL; } }
>
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQIcBAEBCAAGBQJWHYt7AAoJEHYLnGJQkpH7f+0P/3Tc7KO87UBovvZTXh/cxQXp
0sXh3nWd/M8mBokqHPFFKTuX5ci8qJNlRBKnQp9n0GKGe/tlIronnJLoV3hdFZun
Sh6JW96SyomW7FCz2ZxppE7sasvcfcEclyg+suMtiCzFUnbu8xYRmIAgf8QC3GUk
PhcD5JfZsUbExA9Q9FXAmiI6s7PYH5GPz5Zdu1I4t+Dihuvsh8ztEkdKiRTZjCfn
p7yVq1+td0KO011dFWioRfQszLzV7luftPCHoBeZN2b2jb32v9HaQHuQ91GlY0W/
zNO1zgUQpxbb3cbkBmhT8lbQiOr160MPqeKm3lu9fs2MrXKg6x+8iPisB6hTSrh6
lIW8WE9SwIlqAVbzd4mbuVa1NngYtXBK4LGi9hTfbUMbZ6hBkuoVIWNwFMxRPdkq
vkYRawoYOiJzVdD4/S1gUC1GrDihZffhxHKG+92Z4o4ktEemvxH0vE7uM9v7XnHz
U2UByrOnFpPabMWroLIwAkei/QKK7c7dvKCP9q2zDiF0BXlqaxO9Pg7eVWXl5l0o
2WKXpUghkklz74RzNe+205jUfcjwAsEMBQIc9+73wcGFAnLy/fh/dnJIrIyyrSnf
DGUbFzGXr6k4/OBGH5b00Fcq18UYrbty2OVXu1qf5bZf0egod8D751QPnQweMHME
cP30MH0ZEVPWGchbbq28
=EzjZ
-----END PGP SIGNATURE-----
More information about the Nouveau
mailing list