Initial support for pre-i915 PLL programming. Untested.

This commit is contained in:
Eric Anholt 2006-04-12 12:16:51 -07:00
parent 59f88955f5
commit d6edffee7d
2 changed files with 104 additions and 66 deletions

View File

@ -705,16 +705,20 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# define DPLL_DVO_HIGH_SPEED (1 << 30)
# define DPLL_SYNCLOCK_ENABLE (1 << 29)
# define DPLL_VGA_MODE_DIS (1 << 28)
# define DPLLB_MODE_DAC_SERIAL (1 << 26)
# define DPLLB_MODE_LVDS (2 << 26)
# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24)
# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24)
# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24)
# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24)
# define DPLL_P2_CLOCK_DIV_MASK 0x03000000
# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000
# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */
# define DPLLB_MODE_LVDS (2 << 26) /* i915 */
# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */
# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */
# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */
# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */
# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */
# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */
# define DPLL_FPA01_P1_POS_DIV_MASK_I830 0x001f0000 /* i830 */
# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */
# define PLL_REF_INPUT_DREFCLK (0 << 13)
# define PLL_REF_INPUT_TVCLKIN (2 << 13)
# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */
# define PLL_REF_INPUT_TVCLKINBC (2 << 13)
# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
# define DISPLAY_RATE_SELECT_FPA1 (1 << 8)
# define SDVO_MULTIPLIER_MASK 0x000000ff

View File

@ -66,10 +66,8 @@ i830PllIsValid(ScrnInfoPtr pScrn, int outputs, int refclk, int m1, int m2,
I830Ptr pI830 = I830PTR(pScrn);
int p, m, vco, dotclock;
int min_m1, max_m1, min_m2, max_m2, min_m, max_m, min_n, max_n;
int min_p, max_p;
int min_p1, max_p1, min_p, max_p, min_vco, max_vco, min_dot, max_dot;
min_p = 5;
max_p = 80;
if (pI830->PciInfo->chipType >= PCI_CHIP_I915_G) {
min_m1 = 10;
max_m1 = 20;
@ -79,23 +77,36 @@ i830PllIsValid(ScrnInfoPtr pScrn, int outputs, int refclk, int m1, int m2,
max_m = 120;
min_n = 3;
max_n = 8;
min_p1 = 1;
max_p1 = 8;
if (outputs & PIPE_LCD_ACTIVE) {
min_p = 7;
max_p = 98;
} else {
min_p = 5;
max_p = 80;
}
min_vco = 1400000;
max_vco = 2800000;
min_dot = 20000;
max_dot = 400000;
} else {
min_m1 = 16;
max_m1 = 24;
min_m2 = 7;
max_m2 = 11;
min_m = 90;
max_m = 130;
min_n = 4;
max_n = 8;
if (outputs & PIPE_LCD_ACTIVE) {
min_n = 3;
min_m = 88;
}
min_m1 = 18;
max_m1 = 26;
min_m2 = 6;
max_m2 = 16;
min_m = 96;
max_m = 140;
min_n = 3;
max_n = 16;
min_p1 = 2;
max_p1 = 18;
min_vco = 930000;
max_vco = 1400000;
min_dot = 20000;
max_dot = 350000;
min_p = 4;
max_p = 128;
}
p = p1 * p2;
@ -103,7 +114,7 @@ i830PllIsValid(ScrnInfoPtr pScrn, int outputs, int refclk, int m1, int m2,
vco = refclk * m / n;
dotclock = i830_clock(refclk, m1, m2, n, p1, p2);
if (p1 < 1 || p1 > 8)
if (p1 < min_p1 || p1 > max_p1)
return FALSE;
if (p < min_p || p > max_p)
return FALSE;
@ -117,12 +128,12 @@ i830PllIsValid(ScrnInfoPtr pScrn, int outputs, int refclk, int m1, int m2,
return FALSE;
if (n < min_n || n > max_n)
return FALSE;
if (vco < 1400000 || vco > 2800000)
if (vco < min_vco || vco > max_vco)
return FALSE;
/* XXX: We may need to be checking "Dot clock" depending on the multiplier,
* output, etc., rather than just a single range.
*/
if (dotclock < 20000 || dotclock > 400000)
if (dotclock < min_dot || dotclock > max_dot)
return FALSE;
return TRUE;
@ -215,36 +226,48 @@ i830FindBestPLL(ScrnInfoPtr pScrn, int outputs, int target, int refclk,
I830Ptr pI830 = I830PTR(pScrn);
int m1, m2, n, p1, p2;
int err = target;
int min_m1, max_m1, min_m2, max_m2;
int min_m1, max_m1, min_m2, max_m2, min_n, max_n, min_p1, max_p1;
if (pI830->PciInfo->chipType >= PCI_CHIP_I915_G) {
min_m1 = 10;
max_m1 = 20;
min_m2 = 5;
max_m2 = 9;
min_n = 3;
max_n = 8;
min_p1 = 1;
max_p1 = 8;
if (outputs & PIPE_LCD_ACTIVE) {
if (target < 200000) /* XXX: Is this the right cutoff? */
p2 = 14;
else
p2 = 7;
} else {
if (target < 200000)
p2 = 10;
else
p2 = 5;
}
} else {
min_m1 = 16;
max_m1 = 24;
min_m2 = 7;
max_m2 = 11;
min_m1 = 18;
max_m1 = 26;
min_m2 = 6;
max_m2 = 16;
min_n = 3;
max_n = 16;
min_p1 = 2;
max_p1 = 18;
if (target < 165000)
p2 = 4;
else
p2 = 2;
}
if (outputs & PIPE_LCD_ACTIVE) {
if (target < 200000) /* XXX: Is this the right cutoff? */
p2 = 14;
else
p2 = 7;
} else {
if (target < 200000)
p2 = 10;
else
p2 = 5;
}
for (m1 = min_m1; m1 <= max_m1; m1++) {
for (m2 = min_m2; m2 < max_m2; m2++) {
for (n = 3; n <= 8; n++) {
for (p1 = 1; p1 <= 8; p1++) {
for (n = min_n; n <= max_n; n++) {
for (p1 = min_p1; p1 <= max_p1; p1++) {
int clock, this_err;
if (!i830PllIsValid(pScrn, outputs, refclk, m1, m2, n,
@ -309,7 +332,7 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
CARD32 htot, hblank, hsync, vtot, vblank, vsync, dspcntr;
CARD32 pipesrc, dspsize, adpa;
Bool ok;
int refclk = 96000, pixel_clock;
int refclk, pixel_clock;
int outputs;
ErrorF("Requested pix clock: %d\n", pMode->Clock);
@ -385,6 +408,11 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
pixel_clock = pI830->panel_fixed_clock;
}
if (pI830->PciInfo->chipType >= PCI_CHIP_I915_G) {
refclk = 96000;
} else {
refclk = 48000;
}
ok = i830FindBestPLL(pScrn, outputs, pixel_clock, refclk, &m1, &m2, &n,
&p1, &p2);
if (!ok) {
@ -394,28 +422,34 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
}
dpll = DPLL_VCO_ENABLE | DPLL_VGA_MODE_DIS;
if (outputs & PIPE_LCD_ACTIVE)
dpll |= DPLLB_MODE_LVDS;
else
dpll |= DPLLB_MODE_DAC_SERIAL;
dpll |= (1 << (p1 - 1)) << 16;
switch (p2) {
case 5:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
break;
case 7:
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
break;
case 10:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
break;
case 14:
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
break;
if (pI830->PciInfo->chipType >= PCI_CHIP_I915_G) {
if (outputs & PIPE_LCD_ACTIVE)
dpll |= DPLLB_MODE_LVDS;
else
dpll |= DPLLB_MODE_DAC_SERIAL;
dpll |= (1 << (p1 - 1)) << 16;
switch (p2) {
case 5:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
break;
case 7:
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
break;
case 10:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
break;
case 14:
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
break;
}
} else {
dpll |= (p1 - 2) << 16;
if (p2 == 4)
dpll |= PLL_P2_DIVIDE_BY_4;
}
if (outputs & (PIPE_TV_ACTIVE | PIPE_TV2_ACTIVE))
dpll |= PLL_REF_INPUT_TVCLKIN;
dpll |= PLL_REF_INPUT_TVCLKINBC;
else
dpll |= PLL_REF_INPUT_DREFCLK;
dpll |= SDV0_DEFAULT_MULTIPLIER;