Commit 9830605d authored by Dave Airlie's avatar Dave Airlie

drm/mgag200: fix G200ER pll picking algorithm

The original code was misported from the X driver,

a) an int went to unsigned int, breaking the downward counting testm code
b) the port did the vco/computed clock bits completely wrong.

This fixes an infinite loop on modprobe on some Dell servers with the G200ER
chipset variant.

Found in internal testing.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent f7b83b90
...@@ -468,10 +468,11 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) ...@@ -468,10 +468,11 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
{ {
unsigned int vcomax, vcomin, pllreffreq; unsigned int vcomax, vcomin, pllreffreq;
unsigned int delta, tmpdelta; unsigned int delta, tmpdelta;
unsigned int testr, testn, testm, testo; int testr, testn, testm, testo;
unsigned int p, m, n; unsigned int p, m, n;
unsigned int computed; unsigned int computed, vco;
int tmp; int tmp;
const unsigned int m_div_val[] = { 1, 2, 4, 8 };
m = n = p = 0; m = n = p = 0;
vcomax = 1488000; vcomax = 1488000;
...@@ -490,12 +491,13 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) ...@@ -490,12 +491,13 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
if (delta == 0) if (delta == 0)
break; break;
for (testo = 5; testo < 33; testo++) { for (testo = 5; testo < 33; testo++) {
computed = pllreffreq * (testn + 1) / vco = pllreffreq * (testn + 1) /
(testr + 1); (testr + 1);
if (computed < vcomin) if (vco < vcomin)
continue; continue;
if (computed > vcomax) if (vco > vcomax)
continue; continue;
computed = vco / (m_div_val[testm] * (testo + 1));
if (computed > clock) if (computed > clock)
tmpdelta = computed - clock; tmpdelta = computed - clock;
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment