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 @@
*
* 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.
*
* 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
* 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) {
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) {
if (f2 < f1) {
f2 = f1 - f2;
......@@ -52,6 +56,7 @@ static unsigned int g450_nextpll(CPMINFO const struct matrox_pll_limits* pi, uns
m = (mnp >> 16) & 0xFF;
p = mnp & 0xFF;
do {
if (m == 0 || m == 0xFF) {
if (m == 0) {
if (p & 0x40) {
......@@ -86,6 +91,7 @@ static unsigned int g450_nextpll(CPMINFO const struct matrox_pll_limits* pi, uns
m--;
}
n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
} while (n < 0x03 || n > 0x7A);
return (m << 16) | (n << 8) | p;
}
......@@ -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)) {
g450_setpll(PMINFO mnp, pll);
}
......@@ -385,10 +391,8 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
unsigned int vco;
unsigned int delta;
if ((mnp & 0xFF00) < 0x0300 || (mnp & 0xFF00) > 0x7A00) {
continue;
}
vco = g450_mnp2vco(PMINFO mnp);
#if 0
if (pll == M_VIDEO_PLL) {
unsigned int big, small;
......@@ -406,6 +410,7 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
continue;
}
}
#endif
delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
for (idx = mnpcount; idx > 0; idx--) {
/* == is important; due to nextpll algorithm we get
......@@ -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 */
if (!mnpcount) {
return 1;
return -EBUSY;
}
{
unsigned long flags;
......@@ -435,15 +440,15 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
matroxfb_DAC_lock_irqsave(flags);
mnp = g450_checkcache(PMINFO ci, mnparray[0]);
if (mnp != NO_MORE_MNP) {
g450_setpll_cond(PMINFO mnp, pll);
matroxfb_g450_setpll_cond(PMINFO mnp, pll);
} else {
mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount);
g450_addcache(ci, mnparray[0], mnp);
}
updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll);
matroxfb_DAC_unlock_irqrestore(flags);
return mnp;
}
return 0;
}
/* 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) {
}
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_LICENSE("GPL");
......@@ -4,5 +4,7 @@
#include "matroxfb_base.h"
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__ */
This diff is collapsed.
......@@ -146,6 +146,8 @@ void DAC1064_global_restore(WPMINFO2);
#define M1064_XPWRCTRL 0xA0
#define M1064_XPANMODE 0xA2
enum POS1064 {
POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL,
POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE,
......@@ -156,7 +158,7 @@ enum POS1064 {
POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST,
POS1064_XCRCBITSEL,
POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH,
POS1064_XOUTPUTCONN };
POS1064_XOUTPUTCONN, POS1064_XPANMODE, POS1064_XPWRCTRL };
#endif /* __MATROXFB_DAC1064_H__ */
......@@ -796,6 +796,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
int out;
matroxfb_var2my(var, &mt);
mt.crtc = MATROXFB_SRC_CRTC1;
/* CRTC1 delays */
switch (var->bits_per_pixel) {
case 0: mt.delay = 31 + 0; break;
......@@ -818,6 +819,8 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
}
}
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));
if (display->type == FB_TYPE_TEXT) {
if (fontheight(display))
......
......@@ -288,6 +288,8 @@ static inline void mga_iounmap(vaddr_t va) {
struct my_timming {
unsigned int pixclock;
int mnp;
unsigned int crtc;
unsigned int HDisplay;
unsigned int HSyncStart;
unsigned int HSyncEnd;
......@@ -364,6 +366,10 @@ struct mavenregs {
u_int16_t hcorr;
};
struct matrox_crtc2 {
u_int32_t ctl;
};
struct matrox_hw_state {
u_int32_t MXoptionReg;
unsigned char DACclk[6];
......@@ -381,10 +387,7 @@ struct matrox_hw_state {
/* TVOut only */
struct mavenregs maven;
/* CRTC2 only */
/* u_int32_t TBD */
unsigned int vidclk;
struct matrox_crtc2 crtc2;
};
struct matrox_accel_data {
......@@ -441,6 +444,12 @@ struct matrox_fb_info {
struct pci_dev* pcidev;
struct {
unsigned int pixclock;
int mnp;
} crtc1;
struct {
unsigned int pixclock;
int mnp;
struct matroxfb_dh_fb_info* info;
struct rw_semaphore lock;
} crtc2;
......
......@@ -142,7 +142,7 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
mt->VSyncEnd >>= 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(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
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,
mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */
{
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... */
mga_outl(0x3C2C, pos); /* field #1 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,
}
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 */
if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
tmp |= 0x00000100;
if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
tmp |= 0x00000200;
mga_outl(0x3C44, tmp);
mga_outl(0x3C4C, 0); /* data control */
}
static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
MINFO_FROM(m2info->primary_dev);
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,
......@@ -417,6 +434,7 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
int cnt;
matroxfb_var2my(var, &mt);
mt.crtc = MATROXFB_SRC_CRTC2;
/* CRTC2 delay */
mt.delay = 34;
......@@ -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);
if (cnt) {
matroxfb_dh_restore(m2info, &mt, p, mode, pos);
......
......@@ -20,16 +20,28 @@
#include <asm/uaccess.h>
static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
#define minfo ((struct matrox_fb_info*)md)
ACCESS_FBINFO(hw).vidclk = mt->pixclock;
#undef minfo
MINFO_FROM(md);
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;
}
static int matroxfb_g450_program(void* md) {
#define minfo ((struct matrox_fb_info*)md)
matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(hw).vidclk, M_VIDEO_PLL);
#undef minfo
return 0;
}
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;
}
......@@ -39,6 +51,11 @@ static struct matrox_altout matroxfb_g450_altout = {
.program = matroxfb_g450_program,
};
static struct matrox_altout matroxfb_g450_dvi = {
.name = "DVI output",
.compute = g450_dvi_compute,
};
void matroxfb_g450_connect(WPMINFO2) {
if (ACCESS_FBINFO(devflags.g450dac)) {
down_write(&ACCESS_FBINFO(altout.lock));
......@@ -46,6 +63,10 @@ void matroxfb_g450_connect(WPMINFO2) {
ACCESS_FBINFO(outputs[1]).data = MINFO;
ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout;
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));
}
}
......@@ -57,6 +78,10 @@ void matroxfb_g450_shutdown(WPMINFO2) {
ACCESS_FBINFO(outputs[1]).output = NULL;
ACCESS_FBINFO(outputs[1]).data = NULL;
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));
}
}
......@@ -64,6 +89,6 @@ void matroxfb_g450_shutdown(WPMINFO2) {
EXPORT_SYMBOL(matroxfb_g450_connect);
EXPORT_SYMBOL(matroxfb_g450_shutdown);
MODULE_AUTHOR("(c) 2000-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Matrox G450 secondary output driver");
MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Matrox G450/G550 output driver");
MODULE_LICENSE("GPL");
......@@ -146,6 +146,7 @@ void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
mt->pixclock = 1000000000 / pixclock;
if (mt->pixclock < 1) mt->pixclock = 1;
mt->mnp = -1;
mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
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