Commit 705e41f8 authored by Petr Vandrovec's avatar Petr Vandrovec

matroxfb DVI updates:

Handle DVI output on G450/G550.
Powerdown unused portions of G450/G550 DAC.
Split G450/G550 DAC from older DAC1064 handling.
Modify PLL setting when both CRTCs use same pixel clocks.
parent 9f8213f9
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* *
* Hardware accelerated Matrox PCI cards - G450/G550 PLL control. * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
* *
* (c) 2001 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
* *
* Portions Copyright (c) 2001 Matrox Graphics Inc. * Portions Copyright (c) 2001 Matrox Graphics Inc.
* *
* Version: 1.62 2001/11/29 * Version: 1.64 2002/06/10
* *
* This file is subject to the terms and conditions of the GNU General Public * This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for * License. See the file COPYING in the main directory of this archive for
...@@ -33,6 +33,10 @@ static unsigned int g450_mnp2vco(CPMINFO unsigned int mnp) { ...@@ -33,6 +33,10 @@ static unsigned int g450_mnp2vco(CPMINFO unsigned int mnp) {
return (ACCESS_FBINFO(features).pll.ref_freq * n + (m >> 1)) / m; return (ACCESS_FBINFO(features).pll.ref_freq * n + (m >> 1)) / m;
} }
unsigned int g450_mnp2f(CPMINFO unsigned int mnp) {
return g450_vco2f(mnp, g450_mnp2vco(PMINFO mnp));
}
static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) { static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
if (f2 < f1) { if (f2 < f1) {
f2 = f1 - f2; f2 = f1 - f2;
...@@ -52,40 +56,42 @@ static unsigned int g450_nextpll(CPMINFO const struct matrox_pll_limits* pi, uns ...@@ -52,40 +56,42 @@ static unsigned int g450_nextpll(CPMINFO const struct matrox_pll_limits* pi, uns
m = (mnp >> 16) & 0xFF; m = (mnp >> 16) & 0xFF;
p = mnp & 0xFF; p = mnp & 0xFF;
if (m == 0 || m == 0xFF) { do {
if (m == 0) { if (m == 0 || m == 0xFF) {
if (p & 0x40) { if (m == 0) {
return NO_MORE_MNP; if (p & 0x40) {
return NO_MORE_MNP;
}
if (p & 3) {
p--;
} else {
p = 0x40;
}
tvco >>= 1;
if (tvco < pi->vcomin) {
return NO_MORE_MNP;
}
*fvco = tvco;
} }
if (p & 3) {
p--; p &= 0x43;
if (tvco < 550000) {
/* p |= 0x00; */
} else if (tvco < 700000) {
p |= 0x08;
} else if (tvco < 1000000) {
p |= 0x10;
} else if (tvco < 1150000) {
p |= 0x18;
} else { } else {
p = 0x40; p |= 0x20;
} }
tvco >>= 1; m = 9;
if (tvco < pi->vcomin) {
return NO_MORE_MNP;
}
*fvco = tvco;
}
p &= 0x43;
if (tvco < 550000) {
/* p |= 0x00; */
} else if (tvco < 700000) {
p |= 0x08;
} else if (tvco < 1000000) {
p |= 0x10;
} else if (tvco < 1150000) {
p |= 0x18;
} else { } else {
p |= 0x20; m--;
} }
m = 9; n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
} else { } while (n < 0x03 || n > 0x7A);
m--;
}
n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
return (m << 16) | (n << 8) | p; return (m << 16) | (n << 8) | p;
} }
...@@ -219,7 +225,7 @@ static void updatehwstate_clk(struct matrox_hw_state* hw, unsigned int mnp, unsi ...@@ -219,7 +225,7 @@ static void updatehwstate_clk(struct matrox_hw_state* hw, unsigned int mnp, unsi
} }
} }
static inline void g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) { void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
if (g450_cmppll(PMINFO mnp, pll)) { if (g450_cmppll(PMINFO mnp, pll)) {
g450_setpll(PMINFO mnp, pll); g450_setpll(PMINFO mnp, pll);
} }
...@@ -385,10 +391,8 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll, ...@@ -385,10 +391,8 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
unsigned int vco; unsigned int vco;
unsigned int delta; unsigned int delta;
if ((mnp & 0xFF00) < 0x0300 || (mnp & 0xFF00) > 0x7A00) {
continue;
}
vco = g450_mnp2vco(PMINFO mnp); vco = g450_mnp2vco(PMINFO mnp);
#if 0
if (pll == M_VIDEO_PLL) { if (pll == M_VIDEO_PLL) {
unsigned int big, small; unsigned int big, small;
...@@ -406,6 +410,7 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll, ...@@ -406,6 +410,7 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
continue; continue;
} }
} }
#endif
delta = pll_freq_delta(fout, g450_vco2f(mnp, vco)); delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
for (idx = mnpcount; idx > 0; idx--) { for (idx = mnpcount; idx > 0; idx--) {
/* == is important; due to nextpll algorithm we get /* == is important; due to nextpll algorithm we get
...@@ -426,7 +431,7 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll, ...@@ -426,7 +431,7 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
} }
/* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */ /* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
if (!mnpcount) { if (!mnpcount) {
return 1; return -EBUSY;
} }
{ {
unsigned long flags; unsigned long flags;
...@@ -435,15 +440,15 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll, ...@@ -435,15 +440,15 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
matroxfb_DAC_lock_irqsave(flags); matroxfb_DAC_lock_irqsave(flags);
mnp = g450_checkcache(PMINFO ci, mnparray[0]); mnp = g450_checkcache(PMINFO ci, mnparray[0]);
if (mnp != NO_MORE_MNP) { if (mnp != NO_MORE_MNP) {
g450_setpll_cond(PMINFO mnp, pll); matroxfb_g450_setpll_cond(PMINFO mnp, pll);
} else { } else {
mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount); mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount);
g450_addcache(ci, mnparray[0], mnp); g450_addcache(ci, mnparray[0], mnp);
} }
updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll); updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll);
matroxfb_DAC_unlock_irqrestore(flags); matroxfb_DAC_unlock_irqrestore(flags);
return mnp;
} }
return 0;
} }
/* It must be greater than number of possible PLL values. /* It must be greater than number of possible PLL values.
...@@ -465,8 +470,10 @@ int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll) { ...@@ -465,8 +470,10 @@ int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll) {
} }
EXPORT_SYMBOL(matroxfb_g450_setclk); EXPORT_SYMBOL(matroxfb_g450_setclk);
EXPORT_SYMBOL(g450_mnp2f);
EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
MODULE_AUTHOR("(c) 2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Matrox G450/G550 PLL driver"); MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -4,5 +4,7 @@ ...@@ -4,5 +4,7 @@
#include "matroxfb_base.h" #include "matroxfb_base.h"
int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll); int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll);
unsigned int g450_mnp2f(CPMINFO unsigned int mnp);
void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll);
#endif /* __G450_PLL_H__ */ #endif /* __G450_PLL_H__ */
...@@ -161,37 +161,20 @@ static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsi ...@@ -161,37 +161,20 @@ static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsi
unsigned int p; unsigned int p;
DBG("DAC1064_calcclock") DBG("DAC1064_calcclock")
/* only for devices older than G450 */
fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p); fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
if (ACCESS_FBINFO(devflags.g450dac)) { p = (1 << p) - 1;
if (fvco <= 300000) /* 276-324 */ if (fvco <= 100000)
; ;
else if (fvco <= 400000) /* 378-438 */ else if (fvco <= 140000)
p |= 0x08; p |= 0x08;
else if (fvco <= 550000) /* 540-567 */ else if (fvco <= 180000)
p |= 0x10; p |= 0x10;
else if (fvco <= 690000) /* 675-695 */ else
p |= 0x18; p |= 0x18;
else if (fvco <= 800000) /* 776-803 */
p |= 0x20;
else if (fvco <= 891000) /* 891-891 */
p |= 0x28;
else if (fvco <= 940000) /* 931-945 */
p |= 0x30;
else /* <959 */
p |= 0x38;
} else {
p = (1 << p) - 1;
if (fvco <= 100000)
;
else if (fvco <= 140000)
p |= 0x08;
else if (fvco <= 180000)
p |= 0x10;
else
p |= 0x18;
}
*post = p; *post = p;
} }
...@@ -293,31 +276,164 @@ static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) { ...@@ -293,31 +276,164 @@ static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) {
hw->MXoptionReg = mx; hw->MXoptionReg = mx;
} }
static void g450_set_plls(WPMINFO2) {
u_int32_t c2_ctl;
unsigned int pxc;
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
int pixelmnp;
int videomnp;
c2_ctl = hw->crtc2.ctl & ~0x4007; /* Clear PLL + enable for CRTC2 */
c2_ctl |= 0x0001; /* Enable CRTC2 */
hw->DACreg[POS1064_XPWRCTRL] &= ~0x02; /* Stop VIDEO PLL */
pixelmnp = ACCESS_FBINFO(crtc1).mnp;
videomnp = ACCESS_FBINFO(crtc2).mnp;
if (videomnp < 0) {
c2_ctl &= ~0x0001; /* Disable CRTC2 */
hw->DACreg[POS1064_XPWRCTRL] &= ~0x10; /* Powerdown CRTC2 */
} else if (ACCESS_FBINFO(crtc2).pixclock == ACCESS_FBINFO(features).pll.ref_freq) {
c2_ctl |= 0x4002; /* Use reference directly */
} else if (videomnp == pixelmnp) {
c2_ctl |= 0x0004; /* Use pixel PLL */
} else {
if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) {
/* PIXEL and VIDEO PLL must not use same frequency. We modify N
of PIXEL PLL in such case because of VIDEO PLL may be source
of TVO clocks, and chroma subcarrier is derived from its
pixel clocks */
pixelmnp += 0x000100;
}
c2_ctl |= 0x0006; /* Use video PLL */
hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
matroxfb_g450_setpll_cond(PMINFO videomnp, M_VIDEO_PLL);
}
hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
if (pixelmnp >= 0) {
hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
matroxfb_g450_setpll_cond(PMINFO pixelmnp, M_PIXEL_PLL_C);
}
if (c2_ctl != hw->crtc2.ctl) {
hw->crtc2.ctl = c2_ctl;
mga_outl(0x3C10, c2_ctl);
}
pxc = ACCESS_FBINFO(crtc1).pixclock;
if (pxc == 0 || ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC2) {
pxc = ACCESS_FBINFO(crtc2).pixclock;
}
if (ACCESS_FBINFO(chip) == MGA_G550) {
if (pxc < 45000) {
hw->DACreg[POS1064_XPANMODE] = 0x00; /* 0-50 */
} else if (pxc < 55000) {
hw->DACreg[POS1064_XPANMODE] = 0x08; /* 34-62 */
} else if (pxc < 70000) {
hw->DACreg[POS1064_XPANMODE] = 0x10; /* 42-78 */
} else if (pxc < 85000) {
hw->DACreg[POS1064_XPANMODE] = 0x18; /* 62-92 */
} else if (pxc < 100000) {
hw->DACreg[POS1064_XPANMODE] = 0x20; /* 74-108 */
} else if (pxc < 115000) {
hw->DACreg[POS1064_XPANMODE] = 0x28; /* 94-122 */
} else if (pxc < 125000) {
hw->DACreg[POS1064_XPANMODE] = 0x30; /* 108-132 */
} else {
hw->DACreg[POS1064_XPANMODE] = 0x38; /* 120-168 */
}
} else {
/* G450 */
if (pxc < 45000) {
hw->DACreg[POS1064_XPANMODE] = 0x00; /* 0-54 */
} else if (pxc < 65000) {
hw->DACreg[POS1064_XPANMODE] = 0x08; /* 38-70 */
} else if (pxc < 85000) {
hw->DACreg[POS1064_XPANMODE] = 0x10; /* 56-96 */
} else if (pxc < 105000) {
hw->DACreg[POS1064_XPANMODE] = 0x18; /* 80-114 */
} else if (pxc < 135000) {
hw->DACreg[POS1064_XPANMODE] = 0x20; /* 102-144 */
} else if (pxc < 160000) {
hw->DACreg[POS1064_XPANMODE] = 0x28; /* 132-166 */
} else if (pxc < 175000) {
hw->DACreg[POS1064_XPANMODE] = 0x30; /* 154-182 */
} else {
hw->DACreg[POS1064_XPANMODE] = 0x38; /* 170-204 */
}
}
}
void DAC1064_global_init(WPMINFO2) { void DAC1064_global_init(WPMINFO2) {
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK; hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN; hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL; hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
hw->DACreg[POS1064_XOUTPUTCONN] = 0x01; /* output #1 enabled */ if (ACCESS_FBINFO(devflags.g450dac)) {
if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) { hw->DACreg[POS1064_XPWRCTRL] = 0x1F; /* powerup everything */
if (ACCESS_FBINFO(devflags.g450dac)) { hw->DACreg[POS1064_XOUTPUTCONN] = 0x00; /* disable outputs */
hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL2; hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
hw->DACreg[POS1064_XOUTPUTCONN] = 0x05; /* output #1 enabled; CRTC1 connected to output #2 */ switch (ACCESS_FBINFO(outputs[0]).src) {
} else { case MATROXFB_SRC_CRTC1:
case MATROXFB_SRC_CRTC2:
hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01; /* enable output; CRTC1/2 selection is in CRTC2 ctl */
break;
case MATROXFB_SRC_NONE:
hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN;
break;
}
switch (ACCESS_FBINFO(outputs[1]).src) {
case MATROXFB_SRC_CRTC1:
hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04;
break;
case MATROXFB_SRC_CRTC2:
if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_MONITOR) {
hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08;
} else {
hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C;
}
break;
case MATROXFB_SRC_NONE:
hw->DACreg[POS1064_XPWRCTRL] &= ~0x01; /* Poweroff DAC2 */
break;
}
switch (ACCESS_FBINFO(outputs[2]).src) {
case MATROXFB_SRC_CRTC1:
hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20;
break;
case MATROXFB_SRC_CRTC2:
hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40;
break;
case MATROXFB_SRC_NONE:
#if 0
/* HELP! If we boot without DFP connected to DVI, we can
poweroff TMDS. But if we boot with DFP connected,
TMDS generated clocks are used instead of ALL pixclocks
available... If someone knows which register
handles it, please reveal this secret to me... */
hw->DACreg[POS1064_XPWRCTRL] &= ~0x04; /* Poweroff TMDS */
#endif
break;
}
/* Now set timming related variables... */
g450_set_plls(PMINFO2);
} else {
if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) {
hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT; hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12; hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
} } else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
} else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) { hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12; } else if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1)
hw->DACreg[POS1064_XOUTPUTCONN] = 0x09; /* output #1 enabled; CRTC2 connected to output #2 */ hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
} else if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) else
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12; hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
else
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE) if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE)
hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN; hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
}
} }
void DAC1064_global_restore(WPMINFO2) { void DAC1064_global_restore(WPMINFO2) {
...@@ -329,8 +445,9 @@ void DAC1064_global_restore(WPMINFO2) { ...@@ -329,8 +445,9 @@ void DAC1064_global_restore(WPMINFO2) {
outDAC1064(PMINFO 0x20, 0x04); outDAC1064(PMINFO 0x20, 0x04);
outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type)); outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type));
if (ACCESS_FBINFO(devflags.g450dac)) { if (ACCESS_FBINFO(devflags.g450dac)) {
outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC); /* only matrox know... */ outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);
outDAC1064(PMINFO M1064_XPWRCTRL, 0x1F); /* powerup everything */ outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
outDAC1064(PMINFO M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]); outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]);
} }
} }
...@@ -368,13 +485,13 @@ static int DAC1064_init_1(WPMINFO struct my_timming* m, struct display *p) { ...@@ -368,13 +485,13 @@ static int DAC1064_init_1(WPMINFO struct my_timming* m, struct display *p) {
return 1; /* unsupported depth */ return 1; /* unsupported depth */
} }
} }
DAC1064_global_init(PMINFO2);
hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl); hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK; hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN; hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10; hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10;
hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18; hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18;
DAC1064_global_init(PMINFO2);
return 0; return 0;
} }
...@@ -471,13 +588,8 @@ static void DAC1064_restore_2(WPMINFO struct display* p) { ...@@ -471,13 +588,8 @@ static void DAC1064_restore_2(WPMINFO struct display* p) {
#endif #endif
} }
static int m1064_compute(void* outdev, struct my_timming* m) { static int m1064_compute(void* out, struct my_timming* m) {
#define minfo ((struct matrox_fb_info*)outdev) #define minfo ((struct matrox_fb_info*)out)
#ifdef CONFIG_FB_MATROX_G450
if (ACCESS_FBINFO(devflags.g450dac)) {
matroxfb_g450_setclk(PMINFO m->pixclock, M_PIXEL_PLL_C);
} else
#endif
{ {
int i; int i;
int tmout; int tmout;
...@@ -505,8 +617,25 @@ static int m1064_compute(void* outdev, struct my_timming* m) { ...@@ -505,8 +617,25 @@ static int m1064_compute(void* outdev, struct my_timming* m) {
} }
static struct matrox_altout m1064 = { static struct matrox_altout m1064 = {
.name = "Primary output", .name = "Primary output",
.compute = m1064_compute, .compute = m1064_compute,
};
static int g450_compute(void* out, struct my_timming* m) {
#define minfo ((struct matrox_fb_info*)out)
if (m->mnp < 0) {
m->mnp = matroxfb_g450_setclk(PMINFO m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
if (m->mnp >= 0) {
m->pixclock = g450_mnp2f(PMINFO m->mnp);
}
}
#undef minfo
return 0;
}
static struct matrox_altout g450out = {
.name = "Primary output",
.compute = g450_compute,
}; };
#endif /* NEED_DAC1064 */ #endif /* NEED_DAC1064 */
...@@ -701,8 +830,13 @@ static void g450_mclk_init(WPMINFO2) { ...@@ -701,8 +830,13 @@ static void g450_mclk_init(WPMINFO2) {
((ACCESS_FBINFO(values).reg.opt3 & 0x300000) == 0x300000)) { ((ACCESS_FBINFO(values).reg.opt3 & 0x300000) == 0x300000)) {
matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.video), M_VIDEO_PLL); matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.video), M_VIDEO_PLL);
} else { } else {
/* slow down video clocks... */ unsigned long flags;
matroxfb_g450_setclk(PMINFO 0, M_VIDEO_PLL); unsigned int pwr;
matroxfb_DAC_lock_irqsave(flags);
pwr = inDAC1064(PMINFO M1064_XPWRCTRL) & ~0x02;
outDAC1064(PMINFO M1064_XPWRCTRL, pwr);
matroxfb_DAC_unlock_irqrestore(flags);
} }
matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.system), M_SYSTEM_PLL); matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.system), M_SYSTEM_PLL);
...@@ -839,7 +973,11 @@ static int MGAG100_preinit(WPMINFO2) { ...@@ -839,7 +973,11 @@ static int MGAG100_preinit(WPMINFO2) {
ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100 ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
? ACCESS_FBINFO(devflags.sgram) : 1; ? ACCESS_FBINFO(devflags.sgram) : 1;
ACCESS_FBINFO(outputs[0]).output = &m1064; if (ACCESS_FBINFO(devflags.g450dac)) {
ACCESS_FBINFO(outputs[0]).output = &g450out;
} else {
ACCESS_FBINFO(outputs[0]).output = &m1064;
}
ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1; ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
ACCESS_FBINFO(outputs[0]).data = MINFO; ACCESS_FBINFO(outputs[0]).data = MINFO;
ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR; ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
......
...@@ -146,6 +146,8 @@ void DAC1064_global_restore(WPMINFO2); ...@@ -146,6 +146,8 @@ void DAC1064_global_restore(WPMINFO2);
#define M1064_XPWRCTRL 0xA0 #define M1064_XPWRCTRL 0xA0
#define M1064_XPANMODE 0xA2
enum POS1064 { enum POS1064 {
POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL, POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL,
POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE, POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE,
...@@ -156,7 +158,7 @@ enum POS1064 { ...@@ -156,7 +158,7 @@ enum POS1064 {
POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST, POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST,
POS1064_XCRCBITSEL, POS1064_XCRCBITSEL,
POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH, POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH,
POS1064_XOUTPUTCONN }; POS1064_XOUTPUTCONN, POS1064_XPANMODE, POS1064_XPWRCTRL };
#endif /* __MATROXFB_DAC1064_H__ */ #endif /* __MATROXFB_DAC1064_H__ */
...@@ -796,6 +796,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, ...@@ -796,6 +796,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
int out; int out;
matroxfb_var2my(var, &mt); matroxfb_var2my(var, &mt);
mt.crtc = MATROXFB_SRC_CRTC1;
/* CRTC1 delays */ /* CRTC1 delays */
switch (var->bits_per_pixel) { switch (var->bits_per_pixel) {
case 0: mt.delay = 31 + 0; break; case 0: mt.delay = 31 + 0; break;
...@@ -818,6 +819,8 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, ...@@ -818,6 +819,8 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
} }
} }
up_read(&ACCESS_FBINFO(altout).lock); up_read(&ACCESS_FBINFO(altout).lock);
ACCESS_FBINFO(crtc1).pixclock = mt.pixclock;
ACCESS_FBINFO(crtc1).mnp = mt.mnp;
ACCESS_FBINFO(hw_switch->init(PMINFO &mt, display)); ACCESS_FBINFO(hw_switch->init(PMINFO &mt, display));
if (display->type == FB_TYPE_TEXT) { if (display->type == FB_TYPE_TEXT) {
if (fontheight(display)) if (fontheight(display))
......
...@@ -288,6 +288,8 @@ static inline void mga_iounmap(vaddr_t va) { ...@@ -288,6 +288,8 @@ static inline void mga_iounmap(vaddr_t va) {
struct my_timming { struct my_timming {
unsigned int pixclock; unsigned int pixclock;
int mnp;
unsigned int crtc;
unsigned int HDisplay; unsigned int HDisplay;
unsigned int HSyncStart; unsigned int HSyncStart;
unsigned int HSyncEnd; unsigned int HSyncEnd;
...@@ -364,6 +366,10 @@ struct mavenregs { ...@@ -364,6 +366,10 @@ struct mavenregs {
u_int16_t hcorr; u_int16_t hcorr;
}; };
struct matrox_crtc2 {
u_int32_t ctl;
};
struct matrox_hw_state { struct matrox_hw_state {
u_int32_t MXoptionReg; u_int32_t MXoptionReg;
unsigned char DACclk[6]; unsigned char DACclk[6];
...@@ -381,10 +387,7 @@ struct matrox_hw_state { ...@@ -381,10 +387,7 @@ struct matrox_hw_state {
/* TVOut only */ /* TVOut only */
struct mavenregs maven; struct mavenregs maven;
/* CRTC2 only */ struct matrox_crtc2 crtc2;
/* u_int32_t TBD */
unsigned int vidclk;
}; };
struct matrox_accel_data { struct matrox_accel_data {
...@@ -441,7 +444,13 @@ struct matrox_fb_info { ...@@ -441,7 +444,13 @@ struct matrox_fb_info {
struct pci_dev* pcidev; struct pci_dev* pcidev;
struct { struct {
struct matroxfb_dh_fb_info* info; unsigned int pixclock;
int mnp;
} crtc1;
struct {
unsigned int pixclock;
int mnp;
struct matroxfb_dh_fb_info* info;
struct rw_semaphore lock; struct rw_semaphore lock;
} crtc2; } crtc2;
struct { struct {
......
...@@ -142,7 +142,7 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, ...@@ -142,7 +142,7 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
mt->VSyncEnd >>= 1; mt->VSyncEnd >>= 1;
mt->VTotal >>= 1; mt->VTotal >>= 1;
} }
mga_outl(0x3C10, tmp | 0x10000000); /* depth and so on... 0x10000000 is VIDRST polarity */ tmp |= 0x10000000; /* 0x10000000 is VIDRST polarity */
mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8)); mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8));
mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8)); mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1)); mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
...@@ -150,7 +150,7 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, ...@@ -150,7 +150,7 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */ mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */
{ {
u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3); u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3);
if (mt->interlaced) { if (tmp & 0x02000000) {
/* field #0 is smaller, so... */ /* field #0 is smaller, so... */
mga_outl(0x3C2C, pos); /* field #1 vmemory start */ mga_outl(0x3C2C, pos); /* field #1 vmemory start */
mga_outl(0x3C28, pos + linelen); /* field #0 vmemory start */ mga_outl(0x3C28, pos + linelen); /* field #0 vmemory start */
...@@ -160,19 +160,36 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, ...@@ -160,19 +160,36 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
} }
mga_outl(0x3C40, linelen); mga_outl(0x3C40, linelen);
} }
mga_outl(0x3C4C, 0); /* data control */
if (tmp & 0x02000000) {
int i;
mga_outl(0x3C10, tmp & ~0x02000000);
for (i = 0; i < 2; i++) {
unsigned int nl;
unsigned int lastl = 0;
while ((nl = mga_inl(0x3C48) & 0xFFF) >= lastl) {
lastl = nl;
}
}
}
mga_outl(0x3C10, tmp);
ACCESS_FBINFO(hw).crtc2.ctl = tmp;
tmp = 0x0FFF0000; /* line compare */ tmp = 0x0FFF0000; /* line compare */
if (mt->sync & FB_SYNC_HOR_HIGH_ACT) if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
tmp |= 0x00000100; tmp |= 0x00000100;
if (mt->sync & FB_SYNC_VERT_HIGH_ACT) if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
tmp |= 0x00000200; tmp |= 0x00000200;
mga_outl(0x3C44, tmp); mga_outl(0x3C44, tmp);
mga_outl(0x3C4C, 0); /* data control */
} }
static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) { static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
MINFO_FROM(m2info->primary_dev); MINFO_FROM(m2info->primary_dev);
mga_outl(0x3C10, 0x00000004); /* disable CRTC2, CRTC1->DAC1, PLL as clock source */ mga_outl(0x3C10, 0x00000004); /* disable CRTC2, CRTC1->DAC1, PLL as clock source */
ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004;
} }
static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info, static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info,
...@@ -417,6 +434,7 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, ...@@ -417,6 +434,7 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
int cnt; int cnt;
matroxfb_var2my(var, &mt); matroxfb_var2my(var, &mt);
mt.crtc = MATROXFB_SRC_CRTC2;
/* CRTC2 delay */ /* CRTC2 delay */
mt.delay = 34; mt.delay = 34;
...@@ -432,6 +450,8 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, ...@@ -432,6 +450,8 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
} }
} }
} }
ACCESS_FBINFO(crtc2).pixclock = mt.pixclock;
ACCESS_FBINFO(crtc2).mnp = mt.mnp;
up_read(&ACCESS_FBINFO(altout).lock); up_read(&ACCESS_FBINFO(altout).lock);
if (cnt) { if (cnt) {
matroxfb_dh_restore(m2info, &mt, p, mode, pos); matroxfb_dh_restore(m2info, &mt, p, mode, pos);
......
...@@ -20,16 +20,28 @@ ...@@ -20,16 +20,28 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
static int matroxfb_g450_compute(void* md, struct my_timming* mt) { static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
#define minfo ((struct matrox_fb_info*)md) MINFO_FROM(md);
ACCESS_FBINFO(hw).vidclk = mt->pixclock;
#undef minfo if (mt->mnp < 0) {
/* We must program clocks before CRTC2, otherwise interlaced mode
startup may fail */
mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
}
return 0; return 0;
} }
static int matroxfb_g450_program(void* md) { static int matroxfb_g450_program(void* md) {
#define minfo ((struct matrox_fb_info*)md) return 0;
matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(hw).vidclk, M_VIDEO_PLL); }
#undef minfo
static int g450_dvi_compute(void* md, struct my_timming* mt) {
MINFO_FROM(md);
if (mt->mnp < 0) {
mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
}
return 0; return 0;
} }
...@@ -39,6 +51,11 @@ static struct matrox_altout matroxfb_g450_altout = { ...@@ -39,6 +51,11 @@ static struct matrox_altout matroxfb_g450_altout = {
.program = matroxfb_g450_program, .program = matroxfb_g450_program,
}; };
static struct matrox_altout matroxfb_g450_dvi = {
.name = "DVI output",
.compute = g450_dvi_compute,
};
void matroxfb_g450_connect(WPMINFO2) { void matroxfb_g450_connect(WPMINFO2) {
if (ACCESS_FBINFO(devflags.g450dac)) { if (ACCESS_FBINFO(devflags.g450dac)) {
down_write(&ACCESS_FBINFO(altout.lock)); down_write(&ACCESS_FBINFO(altout.lock));
...@@ -46,6 +63,10 @@ void matroxfb_g450_connect(WPMINFO2) { ...@@ -46,6 +63,10 @@ void matroxfb_g450_connect(WPMINFO2) {
ACCESS_FBINFO(outputs[1]).data = MINFO; ACCESS_FBINFO(outputs[1]).data = MINFO;
ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout; ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout;
ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR; ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
ACCESS_FBINFO(outputs[2]).data = MINFO;
ACCESS_FBINFO(outputs[2]).output = &matroxfb_g450_dvi;
ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
up_write(&ACCESS_FBINFO(altout.lock)); up_write(&ACCESS_FBINFO(altout.lock));
} }
} }
...@@ -57,6 +78,10 @@ void matroxfb_g450_shutdown(WPMINFO2) { ...@@ -57,6 +78,10 @@ void matroxfb_g450_shutdown(WPMINFO2) {
ACCESS_FBINFO(outputs[1]).output = NULL; ACCESS_FBINFO(outputs[1]).output = NULL;
ACCESS_FBINFO(outputs[1]).data = NULL; ACCESS_FBINFO(outputs[1]).data = NULL;
ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR; ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
ACCESS_FBINFO(outputs[2]).output = NULL;
ACCESS_FBINFO(outputs[2]).data = NULL;
ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
up_write(&ACCESS_FBINFO(altout.lock)); up_write(&ACCESS_FBINFO(altout.lock));
} }
} }
...@@ -64,6 +89,6 @@ void matroxfb_g450_shutdown(WPMINFO2) { ...@@ -64,6 +89,6 @@ void matroxfb_g450_shutdown(WPMINFO2) {
EXPORT_SYMBOL(matroxfb_g450_connect); EXPORT_SYMBOL(matroxfb_g450_connect);
EXPORT_SYMBOL(matroxfb_g450_shutdown); EXPORT_SYMBOL(matroxfb_g450_shutdown);
MODULE_AUTHOR("(c) 2000-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Matrox G450 secondary output driver"); MODULE_DESCRIPTION("Matrox G450/G550 output driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -146,6 +146,7 @@ void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { ...@@ -146,6 +146,7 @@ void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
mt->pixclock = 1000000000 / pixclock; mt->pixclock = 1000000000 / pixclock;
if (mt->pixclock < 1) mt->pixclock = 1; if (mt->pixclock < 1) mt->pixclock = 1;
mt->mnp = -1;
mt->dblscan = var->vmode & FB_VMODE_DOUBLE; mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
mt->interlaced = var->vmode & FB_VMODE_INTERLACED; mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
mt->HDisplay = var->xres; mt->HDisplay = var->xres;
......
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