Commit 062dffea authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://matroxfb.bkbits.net/linux-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 273cbb5a 75273dcb
...@@ -387,8 +387,7 @@ CONFIG_FB_MATROX ...@@ -387,8 +387,7 @@ CONFIG_FB_MATROX
Say Y here if you have a Matrox Millennium, Matrox Millennium II, Say Y here if you have a Matrox Millennium, Matrox Millennium II,
Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video, Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video,
Matrox G400, G450 or G550 card in your box. At this time, support for Matrox G400, G450 or G550 card in your box.
the G-series digital output is almost non-existant.
This driver is also available as a module ( = code which can be This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). inserted and removed from the running kernel whenever you want).
...@@ -413,7 +412,7 @@ CONFIG_FB_MATROX_MYSTIQUE ...@@ -413,7 +412,7 @@ CONFIG_FB_MATROX_MYSTIQUE
packed pixel and 32 bpp packed pixel. You can also use font widths packed pixel and 32 bpp packed pixel. You can also use font widths
different from 8. different from 8.
CONFIG_FB_MATROX_G100 CONFIG_FB_MATROX_G450
Say Y here if you have a Matrox G100, G200, G400, G450 or G550 based Say Y here if you have a Matrox G100, G200, G400, G450 or G550 based
video card. If you select "Advanced lowlevel driver options", you video card. If you select "Advanced lowlevel driver options", you
should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed
...@@ -423,11 +422,35 @@ CONFIG_FB_MATROX_G100 ...@@ -423,11 +422,35 @@ CONFIG_FB_MATROX_G100
If you need support for G400 secondary head, you must first say Y to If you need support for G400 secondary head, you must first say Y to
"I2C support" and "I2C bit-banging support" in the character devices "I2C support" and "I2C bit-banging support" in the character devices
section, and then to "Matrox I2C support" and "G400 second head section, and then to "Matrox I2C support" and "G400 second head
support" here in the framebuffer section. support" here in the framebuffer section. G450/G550 secondary head
and digital output are supported without additional modules.
The driver starts in monitor mode. You must use the matroxset tool
(available at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to
swap primary and secondary head outputs, or to change output mode.
Secondary head driver always start in 640x480 resolution and you
must use fbset to change it.
Do not forget that second head supports only 16 and 32 bpp
packed pixels, so it is a good idea to compile them into the kernel
too. You can use only some font widths, as the driver uses generic
painting procedures (the secondary head does not use acceleration
engine).
If you have G550, you must also compile support for G450/G550 secondary G450/G550 hardware can display TV picture only from secondary CRTC,
head into kernel, otherwise picture will be shown only on output you and it performs no scaling, so picture must have 525 or 625 lines.
are probably not using...
CONFIG_FB_MATROX_G100A
Say Y here if you have a Matrox G100, G200 or G400 based
video card. If you select "Advanced lowlevel driver options", you
should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed
pixel and 32 bpp packed pixel. You can also use font widths
different from 8.
If you need support for G400 secondary head, you must first say Y to
"I2C support" and "I2C bit-banging support" in the character devices
section, and then to "Matrox I2C support" and "G400 second head
support" here in the framebuffer section.
CONFIG_FB_MATROX_I2C CONFIG_FB_MATROX_I2C
This drivers creates I2C buses which are needed for accessing the This drivers creates I2C buses which are needed for accessing the
...@@ -470,27 +493,6 @@ CONFIG_FB_MATROX_MAVEN ...@@ -470,27 +493,6 @@ CONFIG_FB_MATROX_MAVEN
painting procedures (the secondary head does not use acceleration painting procedures (the secondary head does not use acceleration
engine). engine).
CONFIG_FB_MATROX_G450
Say Y or M here if you want to use a secondary head (meaning two
monitors in parallel) on G450, or if you are using analog output
of G550.
If you compile it as module, two modules are created,
matroxfb_crtc2.o and matroxfb_g450.o. Both modules are needed if you
want two independent display devices.
The driver starts in monitor mode and currently does not support
output in TV modes. You must use the matroxset tool (available
at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to swap
primary and secondary head outputs. Secondary head driver always
start in 640x480 resolution and you must use fbset to change it.
Also do not forget that second head supports only 16 and 32 bpp
packed pixels, so it is a good idea to compile them into the kernel
too. You can use only some font widths, as the driver uses generic
painting procedures (the secondary head does not use acceleration
engine).
CONFIG_FB_MATROX_MULTIHEAD CONFIG_FB_MATROX_MULTIHEAD
Say Y here if you have more than one (supported) Matrox device in Say Y here if you have more than one (supported) Matrox device in
your computer and you want to use all of them for different monitors your computer and you want to use all of them for different monitors
......
...@@ -130,14 +130,19 @@ if [ "$CONFIG_FB" = "y" ]; then ...@@ -130,14 +130,19 @@ if [ "$CONFIG_FB" = "y" ]; then
if [ "$CONFIG_FB_MATROX" != "n" ]; then if [ "$CONFIG_FB_MATROX" != "n" ]; then
bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE
bool ' G100/G200/G400/G450/G550 support' CONFIG_FB_MATROX_G100 bool ' G100/G200/G400/G450/G550 support' CONFIG_FB_MATROX_G450
if [ "$CONFIG_FB_MATROX_G450" = "n" ]; then
bool ' G100/G200/G400 support' CONFIG_FB_MATROX_G100A
fi
if [ "$CONFIG_FB_MATROX_G450" = "y" -o "$CONFIG_FB_MATROX_G100A" = "y" ]; then
define_bool CONFIG_FB_MATROX_G100 y
fi
if [ "$CONFIG_I2C" != "n" ]; then if [ "$CONFIG_I2C" != "n" ]; then
dep_tristate ' Matrox I2C support' CONFIG_FB_MATROX_I2C $CONFIG_FB_MATROX $CONFIG_I2C_ALGOBIT dep_tristate ' Matrox I2C support' CONFIG_FB_MATROX_I2C $CONFIG_FB_MATROX $CONFIG_I2C_ALGOBIT
if [ "$CONFIG_FB_MATROX_G100" = "y" ]; then if [ "$CONFIG_FB_MATROX_G100" = "y" ]; then
dep_tristate ' G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C dep_tristate ' G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C
fi fi
fi fi
dep_tristate ' G450/G550 second head support (mandatory for G550)' CONFIG_FB_MATROX_G450 $CONFIG_FB_MATROX_G100
bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD
fi fi
tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
......
...@@ -5,16 +5,16 @@ ...@@ -5,16 +5,16 @@
# All of the (potential) objects that export symbols. # All of the (potential) objects that export symbols.
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
export-objs := matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o g450_pll.o export-objs := matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o g450_pll.o matroxfb_g450.o
# Each configuration option enables a list of files. # Each configuration option enables a list of files.
my-obj-$(CONFIG_FB_MATROX_G100) := g450_pll.o my-obj-$(CONFIG_FB_MATROX_G100) += g450_pll.o
my-obj-$(CONFIG_FB_MATROX_G450) += matroxfb_g450.o matroxfb_crtc2.o
obj-$(CONFIG_FB_MATROX) += matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o $(my-obj-y) obj-$(CONFIG_FB_MATROX) += matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o $(my-obj-y)
obj-$(CONFIG_FB_MATROX_I2C) += i2c-matroxfb.o obj-$(CONFIG_FB_MATROX_I2C) += i2c-matroxfb.o
obj-$(CONFIG_FB_MATROX_MAVEN) += matroxfb_maven.o matroxfb_crtc2.o obj-$(CONFIG_FB_MATROX_MAVEN) += matroxfb_maven.o matroxfb_crtc2.o
obj-$(CONFIG_FB_MATROX_G450) += matroxfb_g450.o matroxfb_crtc2.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
......
...@@ -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__ */
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
* *
* (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
* *
* Version: 1.51 2001/01/19 * Version: 1.64 2002/06/10
* *
* See matroxfb_base.c for contributors. * See matroxfb_base.c for contributors.
* *
...@@ -30,6 +30,12 @@ ...@@ -30,6 +30,12 @@
/******************************************************/ /******************************************************/
struct matroxfb_dh_maven_info {
struct i2c_bit_adapter maven;
struct i2c_bit_adapter ddc1;
struct i2c_bit_adapter ddc2;
};
static int matroxfb_read_gpio(struct matrox_fb_info* minfo) { static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
unsigned long flags; unsigned long flags;
int v; int v;
...@@ -40,7 +46,7 @@ static int matroxfb_read_gpio(struct matrox_fb_info* minfo) { ...@@ -40,7 +46,7 @@ static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
return v; return v;
} }
static inline void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) { static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
unsigned long flags; unsigned long flags;
int v; int v;
...@@ -53,7 +59,7 @@ static inline void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int ...@@ -53,7 +59,7 @@ static inline void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int
} }
/* software I2C functions */ /* software I2C functions */
static void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) { static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
if (state) if (state)
state = 0; state = 0;
else else
...@@ -61,68 +67,24 @@ static void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) ...@@ -61,68 +67,24 @@ static void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state)
matroxfb_set_gpio(minfo, ~mask, state); matroxfb_set_gpio(minfo, ~mask, state);
} }
static void matroxfb_maven_setsda(void* data, int state) { static void matroxfb_gpio_setsda(void* data, int state) {
matroxfb_i2c_set(data, MAT_DATA, state); struct i2c_bit_adapter* b = data;
} matroxfb_i2c_set(b->minfo, b->mask.data, state);
static void matroxfb_maven_setscl(void* data, int state) {
matroxfb_i2c_set(data, MAT_CLK, state);
}
static int matroxfb_maven_getsda(void* data) {
return (matroxfb_read_gpio(data) & MAT_DATA) ? 1 : 0;
}
static int matroxfb_maven_getscl(void* data) {
return (matroxfb_read_gpio(data) & MAT_CLK) ? 1 : 0;
}
static void matroxfb_ddc1_setsda(void* data, int state) {
matroxfb_i2c_set(data, DDC1_DATA, state);
}
static void matroxfb_ddc1_setscl(void* data, int state) {
matroxfb_i2c_set(data, DDC1_CLK, state);
}
static int matroxfb_ddc1_getsda(void* data) {
return (matroxfb_read_gpio(data) & DDC1_DATA) ? 1 : 0;
}
static int matroxfb_ddc1_getscl(void* data) {
return (matroxfb_read_gpio(data) & DDC1_CLK) ? 1 : 0;
}
static void matroxfb_ddc1b_setsda(void* data, int state) {
matroxfb_i2c_set(data, DDC1B_DATA, state);
}
static void matroxfb_ddc1b_setscl(void* data, int state) {
matroxfb_i2c_set(data, DDC1B_CLK, state);
}
static int matroxfb_ddc1b_getsda(void* data) {
return (matroxfb_read_gpio(data) & DDC1B_DATA) ? 1 : 0;
}
static int matroxfb_ddc1b_getscl(void* data) {
return (matroxfb_read_gpio(data) & DDC1B_CLK) ? 1 : 0;
} }
static void matroxfb_ddc2_setsda(void* data, int state) { static void matroxfb_gpio_setscl(void* data, int state) {
matroxfb_i2c_set(data, DDC2_DATA, state); struct i2c_bit_adapter* b = data;
matroxfb_i2c_set(b->minfo, b->mask.clock, state);
} }
static void matroxfb_ddc2_setscl(void* data, int state) { static int matroxfb_gpio_getsda(void* data) {
matroxfb_i2c_set(data, DDC2_CLK, state); struct i2c_bit_adapter* b = data;
return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0;
} }
static int matroxfb_ddc2_getsda(void* data) { static int matroxfb_gpio_getscl(void* data) {
return (matroxfb_read_gpio(data) & DDC2_DATA) ? 1 : 0; struct i2c_bit_adapter* b = data;
} return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0;
static int matroxfb_ddc2_getscl(void* data) {
return (matroxfb_read_gpio(data) & DDC2_CLK) ? 1 : 0;
} }
static void matroxfb_dh_inc_use(struct i2c_adapter* dummy) { static void matroxfb_dh_inc_use(struct i2c_adapter* dummy) {
...@@ -133,97 +95,36 @@ static void matroxfb_dh_dec_use(struct i2c_adapter* dummy) { ...@@ -133,97 +95,36 @@ static void matroxfb_dh_dec_use(struct i2c_adapter* dummy) {
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
} }
static struct i2c_adapter matroxmaven_i2c_adapter_template = static struct i2c_adapter matrox_i2c_adapter_template =
{
"",
I2C_HW_B_G400,
NULL,
NULL,
matroxfb_dh_inc_use,
matroxfb_dh_dec_use,
NULL,
NULL,
NULL,
};
static struct i2c_algo_bit_data matroxmaven_i2c_algo_template =
{
NULL,
matroxfb_maven_setsda,
matroxfb_maven_setscl,
matroxfb_maven_getsda,
matroxfb_maven_getscl,
10, 10, 100,
};
static struct i2c_adapter matrox_ddc1_adapter_template =
{
"",
I2C_HW_B_G400, /* DDC */
NULL,
NULL,
matroxfb_dh_inc_use,
matroxfb_dh_dec_use,
NULL,
NULL,
NULL,
};
static struct i2c_algo_bit_data matrox_ddc1_algo_template =
{ {
NULL, .id = I2C_HW_B_G400,
matroxfb_ddc1_setsda, .inc_use = matroxfb_dh_inc_use,
matroxfb_ddc1_setscl, .dec_use = matroxfb_dh_dec_use,
matroxfb_ddc1_getsda,
matroxfb_ddc1_getscl,
10, 10, 100,
};
static struct i2c_algo_bit_data matrox_ddc1b_algo_template =
{
NULL,
matroxfb_ddc1b_setsda,
matroxfb_ddc1b_setscl,
matroxfb_ddc1b_getsda,
matroxfb_ddc1b_getscl,
10, 10, 100,
};
static struct i2c_adapter matrox_ddc2_adapter_template =
{
"",
I2C_HW_B_G400, /* DDC */
NULL,
NULL,
matroxfb_dh_inc_use, /* should increment matroxfb_maven usage too, this DDC is coupled with maven_client */
matroxfb_dh_dec_use, /* should decrement matroxfb_maven usage too */
NULL,
NULL,
NULL,
}; };
static struct i2c_algo_bit_data matrox_ddc2_algo_template = static struct i2c_algo_bit_data matrox_i2c_algo_template =
{ {
NULL, NULL,
matroxfb_ddc2_setsda, matroxfb_gpio_setsda,
matroxfb_ddc2_setscl, matroxfb_gpio_setscl,
matroxfb_ddc2_getsda, matroxfb_gpio_getsda,
matroxfb_ddc2_getscl, matroxfb_gpio_getscl,
10, 10, 100, 10, 10, 100,
}; };
static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo) { static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
unsigned int data, unsigned int clock, const char* name) {
int err; int err;
b->adapter.data = minfo; b->minfo = minfo;
b->mask.data = data;
b->mask.clock = clock;
b->adapter = matrox_i2c_adapter_template;
sprintf(b->adapter.name, name, GET_FB_IDX(minfo->fbcon.node));
b->adapter.data = b;
b->adapter.algo_data = &b->bac; b->adapter.algo_data = &b->bac;
b->bac.data = minfo; b->bac = matrox_i2c_algo_template;
b->bac.data = b;
err = i2c_bit_add_bus(&b->adapter); err = i2c_bit_add_bus(&b->adapter);
b->initialized = !err; b->initialized = !err;
return err; return err;
...@@ -236,50 +137,14 @@ static void i2c_bit_bus_del(struct i2c_bit_adapter* b) { ...@@ -236,50 +137,14 @@ static void i2c_bit_bus_del(struct i2c_bit_adapter* b) {
} }
} }
static inline int i2c_maven_init(struct matroxfb_dh_maven_info* minfo2) {
struct i2c_bit_adapter *b = &minfo2->maven;
b->adapter = matroxmaven_i2c_adapter_template;
b->bac = matroxmaven_i2c_algo_template;
sprintf(b->adapter.name, "MAVEN:fb%u on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
return i2c_bus_reg(b, minfo2->primary_dev);
}
static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) { static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) {
i2c_bit_bus_del(&minfo2->maven); i2c_bit_bus_del(&minfo2->maven);
} }
static inline int i2c_ddc1_init(struct matroxfb_dh_maven_info* minfo2) {
struct i2c_bit_adapter *b = &minfo2->ddc1;
b->adapter = matrox_ddc1_adapter_template;
b->bac = matrox_ddc1_algo_template;
sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
return i2c_bus_reg(b, minfo2->primary_dev);
}
static inline int i2c_ddc1b_init(struct matroxfb_dh_maven_info* minfo2) {
struct i2c_bit_adapter *b = &minfo2->ddc1;
b->adapter = matrox_ddc1_adapter_template;
b->bac = matrox_ddc1b_algo_template;
sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
return i2c_bus_reg(b, minfo2->primary_dev);
}
static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) { static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) {
i2c_bit_bus_del(&minfo2->ddc1); i2c_bit_bus_del(&minfo2->ddc1);
} }
static inline int i2c_ddc2_init(struct matroxfb_dh_maven_info* minfo2) {
struct i2c_bit_adapter *b = &minfo2->ddc2;
b->adapter = matrox_ddc2_adapter_template;
b->bac = matrox_ddc2_algo_template;
sprintf(b->adapter.name, "DDC:fb%u #1 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
return i2c_bus_reg(b, minfo2->primary_dev);
}
static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) { static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) {
i2c_bit_bus_del(&minfo2->ddc2); i2c_bit_bus_del(&minfo2->ddc2);
} }
...@@ -299,24 +164,26 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) { ...@@ -299,24 +164,26 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
matroxfb_DAC_unlock_irqrestore(flags); matroxfb_DAC_unlock_irqrestore(flags);
memset(m2info, 0, sizeof(*m2info)); memset(m2info, 0, sizeof(*m2info));
m2info->maven.minfo = m2info;
m2info->ddc1.minfo = m2info; switch (ACCESS_FBINFO(chip)) {
m2info->ddc2.minfo = m2info; case MGA_2064:
m2info->primary_dev = minfo; case MGA_2164:
err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0 on i2c-matroxfb");
if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2064W || break;
ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W || default:
ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W_AGP) err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0 on i2c-matroxfb");
err = i2c_ddc1b_init(m2info); break;
else }
err = i2c_ddc1_init(m2info);
if (err) if (err)
goto fail_ddc1; goto fail_ddc1;
if (ACCESS_FBINFO(devflags.maven_capable)) { if (ACCESS_FBINFO(devflags.dualhead)) {
err = i2c_ddc2_init(m2info); err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1 on i2c-matroxfb");
if (err) if (err == -ENODEV) {
printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n");
} else if (err)
printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n"); printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
err = i2c_maven_init(m2info); /* Register maven bus even on G450/G550 */
err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, "MAVEN:fb%u on i2c-matroxfb");
if (err) if (err)
printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n"); printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
} }
...@@ -337,10 +204,10 @@ static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) { ...@@ -337,10 +204,10 @@ static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) {
} }
static struct matroxfb_driver i2c_matroxfb = { static struct matroxfb_driver i2c_matroxfb = {
LIST_HEAD_INIT(i2c_matroxfb.node), .node = LIST_HEAD_INIT(i2c_matroxfb.node),
"i2c-matroxfb", .name = "i2c-matroxfb",
i2c_matroxfb_probe, .probe = i2c_matroxfb_probe,
i2c_matroxfb_remove, .remove = i2c_matroxfb_remove,
}; };
static int __init i2c_matroxfb_init(void) { static int __init i2c_matroxfb_init(void) {
...@@ -355,7 +222,7 @@ static void __exit i2c_matroxfb_exit(void) { ...@@ -355,7 +222,7 @@ static void __exit i2c_matroxfb_exit(void) {
matroxfb_unregister_driver(&i2c_matroxfb); matroxfb_unregister_driver(&i2c_matroxfb);
} }
MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards"); MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards");
module_init(i2c_matroxfb_init); module_init(i2c_matroxfb_init);
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
* *
* (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-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.65 2002/08/14
* *
* See matroxfb_base.c for contributors. * See matroxfb_base.c for contributors.
* *
...@@ -150,7 +150,7 @@ static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) { ...@@ -150,7 +150,7 @@ static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) {
return 0; return 0;
} }
static int DAC1064_selhwcursor(WPMINFO struct display* p) { static int DAC1064_selhwcursor(WPMINFO2) {
ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor; ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor;
ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont; ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont;
return 0; return 0;
...@@ -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(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { 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(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { 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(output.ph) & MATROXFB_OUTPUT_CONN_DFP) 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(output.ph) | ACCESS_FBINFO(output.sh)) & MATROXFB_OUTPUT_CONN_PRIMARY) 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,31 +445,32 @@ void DAC1064_global_restore(WPMINFO2) { ...@@ -329,31 +445,32 @@ 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]);
} }
} }
} }
static int DAC1064_init_1(WPMINFO struct my_timming* m, struct display *p) { static int DAC1064_init_1(WPMINFO struct my_timming* m) {
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
DBG("DAC1064_init_1") DBG("DAC1064_init_1")
memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
if (p->type == FB_TYPE_TEXT) { if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
hw->DACreg[POS1064_XMISCCTRL] = M1064_XMISCCTRL_DAC_6BIT; hw->DACreg[POS1064_XMISCCTRL] = M1064_XMISCCTRL_DAC_6BIT;
hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP
| M1064_XMULCTRL_GRAPHICS_PALETIZED; | M1064_XMULCTRL_GRAPHICS_PALETIZED;
} else { } else {
switch (p->var.bits_per_pixel) { switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
/* case 4: not supported by MGA1064 DAC */ /* case 4: not supported by MGA1064 DAC */
case 8: case 8:
hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
break; break;
case 16: case 16:
if (p->var.green.length == 5) if (ACCESS_FBINFO(fbcon).var.green.length == 5)
hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
else else
hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
...@@ -368,22 +485,22 @@ static int DAC1064_init_1(WPMINFO struct my_timming* m, struct display *p) { ...@@ -368,22 +485,22 @@ 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;
} }
static int DAC1064_init_2(WPMINFO struct my_timming* m, struct display* p) { static int DAC1064_init_2(WPMINFO struct my_timming* m) {
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
DBG("DAC1064_init_2") DBG("DAC1064_init_2")
if (p->var.bits_per_pixel > 16) { /* 256 entries */ if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) { /* 256 entries */
int i; int i;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
...@@ -391,8 +508,8 @@ static int DAC1064_init_2(WPMINFO struct my_timming* m, struct display* p) { ...@@ -391,8 +508,8 @@ static int DAC1064_init_2(WPMINFO struct my_timming* m, struct display* p) {
hw->DACpal[i * 3 + 1] = i; hw->DACpal[i * 3 + 1] = i;
hw->DACpal[i * 3 + 2] = i; hw->DACpal[i * 3 + 2] = i;
} }
} else if (p->var.bits_per_pixel > 8) { } else if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 8) {
if (p->var.green.length == 5) { /* 0..31, 128..159 */ if (ACCESS_FBINFO(fbcon).var.green.length == 5) { /* 0..31, 128..159 */
int i; int i;
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
...@@ -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;
...@@ -504,37 +616,26 @@ static int m1064_compute(void* outdev, struct my_timming* m) { ...@@ -504,37 +616,26 @@ static int m1064_compute(void* outdev, struct my_timming* m) {
return 0; return 0;
} }
static int m1064_program(void* outdev) { static struct matrox_altout m1064 = {
/* nothing, hardware is set in m1064_compute */ .name = "Primary output",
return 0; .compute = m1064_compute,
} };
static int m1064_start(void* outdev) {
/* nothing */
return 0;
}
static void m1064_incuse(void* outdev) {
/* nothing yet; MODULE_INC_USE in future... */
}
static void m1064_decuse(void* outdev) {
/* nothing yet; MODULE_DEC_USE in future... */
}
static int m1064_setmode(void* outdev, u_int32_t mode) { static int g450_compute(void* out, struct my_timming* m) {
if (mode != MATROXFB_OUTPUT_MODE_MONITOR) #define minfo ((struct matrox_fb_info*)out)
return -EINVAL; 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; return 0;
} }
static struct matrox_altout m1064 = { static struct matrox_altout g450out = {
m1064_compute, .name = "Primary output",
m1064_program, .compute = g450_compute,
m1064_start,
m1064_incuse,
m1064_decuse,
m1064_setmode
}; };
#endif /* NEED_DAC1064 */ #endif /* NEED_DAC1064 */
...@@ -545,7 +646,7 @@ static int MGA1064_init(WPMINFO struct my_timming* m, struct display* p) { ...@@ -545,7 +646,7 @@ static int MGA1064_init(WPMINFO struct my_timming* m, struct display* p) {
DBG("MGA1064_init") DBG("MGA1064_init")
if (DAC1064_init_1(PMINFO m, p)) return 1; if (DAC1064_init_1(PMINFO m)) return 1;
if (matroxfb_vgaHWinit(PMINFO m, p)) return 1; if (matroxfb_vgaHWinit(PMINFO m, p)) return 1;
hw->MiscOutReg = 0xCB; hw->MiscOutReg = 0xCB;
...@@ -556,7 +657,7 @@ static int MGA1064_init(WPMINFO struct my_timming* m, struct display* p) { ...@@ -556,7 +657,7 @@ static int MGA1064_init(WPMINFO struct my_timming* m, struct display* p) {
if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
hw->CRTCEXT[3] |= 0x40; hw->CRTCEXT[3] |= 0x40;
if (DAC1064_init_2(PMINFO m, p)) return 1; if (DAC1064_init_2(PMINFO m)) return 1;
return 0; return 0;
} }
#endif #endif
...@@ -567,7 +668,7 @@ static int MGAG100_init(WPMINFO struct my_timming* m, struct display* p) { ...@@ -567,7 +668,7 @@ static int MGAG100_init(WPMINFO struct my_timming* m, struct display* p) {
DBG("MGAG100_init") DBG("MGAG100_init")
if (DAC1064_init_1(PMINFO m, p)) return 1; if (DAC1064_init_1(PMINFO m)) return 1;
hw->MXoptionReg &= ~0x2000; hw->MXoptionReg &= ~0x2000;
if (matroxfb_vgaHWinit(PMINFO m, p)) return 1; if (matroxfb_vgaHWinit(PMINFO m, p)) return 1;
...@@ -579,7 +680,7 @@ static int MGAG100_init(WPMINFO struct my_timming* m, struct display* p) { ...@@ -579,7 +680,7 @@ static int MGAG100_init(WPMINFO struct my_timming* m, struct display* p) {
if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
hw->CRTCEXT[3] |= 0x40; hw->CRTCEXT[3] |= 0x40;
if (DAC1064_init_2(PMINFO m, p)) return 1; if (DAC1064_init_2(PMINFO m)) return 1;
return 0; return 0;
} }
#endif /* G100 */ #endif /* G100 */
...@@ -680,7 +781,10 @@ static int MGA1064_preinit(WPMINFO2) { ...@@ -680,7 +781,10 @@ static int MGA1064_preinit(WPMINFO2) {
ACCESS_FBINFO(features.accel.has_cacheflush) = 1; ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor; ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
ACCESS_FBINFO(primout) = &m1064; ACCESS_FBINFO(outputs[0]).output = &m1064;
ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
ACCESS_FBINFO(outputs[0]).data = MINFO;
ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
if (ACCESS_FBINFO(devflags.noinit)) if (ACCESS_FBINFO(devflags.noinit))
return 0; /* do not modify settings */ return 0; /* do not modify settings */
...@@ -726,8 +830,13 @@ static void g450_mclk_init(WPMINFO2) { ...@@ -726,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);
...@@ -864,7 +973,14 @@ static int MGAG100_preinit(WPMINFO2) { ...@@ -864,7 +973,14 @@ 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(primout) = &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]).data = MINFO;
ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
if (ACCESS_FBINFO(devflags.g450dac)) { if (ACCESS_FBINFO(devflags.g450dac)) {
/* we must do this always, BIOS does not do it for us /* we must do this always, BIOS does not do it for us
...@@ -895,8 +1011,7 @@ static int MGAG100_preinit(WPMINFO2) { ...@@ -895,8 +1011,7 @@ static int MGAG100_preinit(WPMINFO2) {
hw->MXoptionReg |= 0x1080; hw->MXoptionReg |= 0x1080;
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
mga_outl(M_CTLWTST, 0x00000300); mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
/* mga_outl(M_CTLWTST, 0x03258A31); */
udelay(100); udelay(100);
mga_outb(0x1C05, 0x00); mga_outb(0x1C05, 0x00);
mga_outb(0x1C05, 0x80); mga_outb(0x1C05, 0x80);
...@@ -947,17 +1062,18 @@ static int MGAG100_preinit(WPMINFO2) { ...@@ -947,17 +1062,18 @@ static int MGAG100_preinit(WPMINFO2) {
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50); pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
if (ACCESS_FBINFO(devflags.memtype) == -1) if (ACCESS_FBINFO(devflags.memtype) == -1)
ACCESS_FBINFO(devflags.memtype) = 0; hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00;
hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10; else
hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
if (ACCESS_FBINFO(devflags.sgram)) if (ACCESS_FBINFO(devflags.sgram))
hw->MXoptionReg |= 0x4000; hw->MXoptionReg |= 0x4000;
mga_outl(M_CTLWTST, 0x042450A1); mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
mga_outl(M_MEMRDBK, 0x00000108); mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
udelay(200); udelay(200);
mga_outl(M_MACCESS, 0x00000000); mga_outl(M_MACCESS, 0x00000000);
mga_outl(M_MACCESS, 0x00008000); mga_outl(M_MACCESS, 0x00008000);
udelay(100); udelay(100);
mga_outl(M_MEMRDBK, 0x00000108); mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
hw->MXoptionReg |= 0x00040020; hw->MXoptionReg |= 0x00040020;
} }
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
......
...@@ -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__ */
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
* *
* (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
* *
* Portions Copyright (c) 2001 Matrox Graphics Inc. * Portions Copyright (c) 2001 Matrox Graphics Inc.
* *
* Version: 1.62 2000/11/29 * Version: 1.65 2002/08/14
* *
* MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
* *
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
#include "matroxfb_Ti3026.h" #include "matroxfb_Ti3026.h"
#include "matroxfb_misc.h" #include "matroxfb_misc.h"
#include "matroxfb_accel.h" #include "matroxfb_accel.h"
#include <linux/matroxfb.h>
#ifdef CONFIG_FB_MATROX_MILLENIUM #ifdef CONFIG_FB_MATROX_MILLENIUM
#define outTi3026 matroxfb_DAC_out #define outTi3026 matroxfb_DAC_out
...@@ -401,7 +402,7 @@ static int matroxfb_ti3026_setfont(struct display* p, int width, int height) { ...@@ -401,7 +402,7 @@ static int matroxfb_ti3026_setfont(struct display* p, int width, int height) {
return 0; return 0;
} }
static int matroxfb_ti3026_selhwcursor(WPMINFO struct display* p) { static int matroxfb_ti3026_selhwcursor(WPMINFO2) {
ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor; ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor;
ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont; ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont;
return 0; return 0;
...@@ -433,7 +434,7 @@ static int Ti3026_setpclk(WPMINFO int clk, struct display* p) { ...@@ -433,7 +434,7 @@ static int Ti3026_setpclk(WPMINFO int clk, struct display* p) {
hw->DACclk[1] = pixfeed; hw->DACclk[1] = pixfeed;
hw->DACclk[2] = pixpost | 0xB0; hw->DACclk[2] = pixpost | 0xB0;
if (p->type == FB_TYPE_TEXT) { if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
hw->DACreg[POS3026_XMEMPLLCTRL] = TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_PIXPLL; hw->DACreg[POS3026_XMEMPLLCTRL] = TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_PIXPLL;
hw->DACclk[3] = 0xFD; hw->DACclk[3] = 0xFD;
hw->DACclk[4] = 0x3D; hw->DACclk[4] = 0x3D;
...@@ -501,7 +502,7 @@ static int Ti3026_init(WPMINFO struct my_timming* m, struct display* p) { ...@@ -501,7 +502,7 @@ static int Ti3026_init(WPMINFO struct my_timming* m, struct display* p) {
DBG("Ti3026_init") DBG("Ti3026_init")
memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg)); memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
if (p->type == FB_TYPE_TEXT) { if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;
hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
hw->DACreg[POS3026_XMUXCTRL] = TVP3026_XMUXCTRL_VGA; hw->DACreg[POS3026_XMUXCTRL] = TVP3026_XMUXCTRL_VGA;
...@@ -568,7 +569,7 @@ static int Ti3026_init(WPMINFO struct my_timming* m, struct display* p) { ...@@ -568,7 +569,7 @@ static int Ti3026_init(WPMINFO struct my_timming* m, struct display* p) {
/* set interleaving */ /* set interleaving */
hw->MXoptionReg &= ~0x00001000; hw->MXoptionReg &= ~0x00001000;
if ((p->type != FB_TYPE_TEXT) && isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000; if ((ACCESS_FBINFO(fbcon).fix.type != FB_TYPE_TEXT) && isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
/* set DAC */ /* set DAC */
Ti3026_setpclk(PMINFO m->pixclock, p); Ti3026_setpclk(PMINFO m->pixclock, p);
...@@ -811,6 +812,10 @@ static void Ti3026_reset(WPMINFO2) { ...@@ -811,6 +812,10 @@ static void Ti3026_reset(WPMINFO2) {
ti3026_ramdac_init(PMINFO2); ti3026_ramdac_init(PMINFO2);
} }
static struct matrox_altout ti3026_output = {
.name = "Primary output",
};
static int Ti3026_preinit(WPMINFO2) { static int Ti3026_preinit(WPMINFO2) {
static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960, static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960,
1024, 1152, 1280, 1600, 1664, 1920, 1024, 1152, 1280, 1600, 1664, 1920,
...@@ -829,6 +834,11 @@ static int Ti3026_preinit(WPMINFO2) { ...@@ -829,6 +834,11 @@ static int Ti3026_preinit(WPMINFO2) {
ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1; ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor; ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor;
ACCESS_FBINFO(outputs[0]).data = MINFO;
ACCESS_FBINFO(outputs[0]).output = &ti3026_output;
ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
if (ACCESS_FBINFO(devflags.noinit)) if (ACCESS_FBINFO(devflags.noinit))
return 0; return 0;
/* preserve VGA I/O, BIOS and PPC */ /* preserve VGA I/O, BIOS and PPC */
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
* *
* (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
* *
* Version: 1.51 2001/06/18 * Version: 1.65 2002/08/14
* *
* MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
* *
...@@ -85,21 +85,21 @@ ...@@ -85,21 +85,21 @@
#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l)) #define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
void matrox_cfbX_init(WPMINFO struct display* p) { void matrox_cfbX_init(WPMINFO2) {
u_int32_t maccess; u_int32_t maccess;
u_int32_t mpitch; u_int32_t mpitch;
u_int32_t mopmode; u_int32_t mopmode;
DBG("matrox_cfbX_init") DBG("matrox_cfbX_init")
mpitch = p->var.xres_virtual; mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual;
if (p->type == FB_TYPE_TEXT) { if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
maccess = 0x00000000; maccess = 0x00000000;
mpitch = (mpitch >> 4) | 0x8000; /* set something */ mpitch = (mpitch >> 4) | 0x8000; /* set something */
mopmode = M_OPMODE_8BPP; mopmode = M_OPMODE_8BPP;
} else { } else {
switch (p->var.bits_per_pixel) { switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
case 4: maccess = 0x00000000; /* accelerate as 8bpp video */ case 4: maccess = 0x00000000; /* accelerate as 8bpp video */
mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */ mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
mopmode = M_OPMODE_4BPP; mopmode = M_OPMODE_4BPP;
...@@ -107,7 +107,7 @@ void matrox_cfbX_init(WPMINFO struct display* p) { ...@@ -107,7 +107,7 @@ void matrox_cfbX_init(WPMINFO struct display* p) {
case 8: maccess = 0x00000000; case 8: maccess = 0x00000000;
mopmode = M_OPMODE_8BPP; mopmode = M_OPMODE_8BPP;
break; break;
case 16: if (p->var.green.length == 5) case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5)
maccess = 0xC0000001; maccess = 0xC0000001;
else else
maccess = 0x40000001; maccess = 0x40000001;
...@@ -816,7 +816,7 @@ static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, i ...@@ -816,7 +816,7 @@ static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, i
static void matrox_text_setup(struct display* p) { static void matrox_text_setup(struct display* p) {
MINFO_FROM_DISP(p); MINFO_FROM_DISP(p);
p->next_line = p->line_length ? p->line_length : ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep)); p->next_line = ACCESS_FBINFO(fbcon).fix.line_length ? ACCESS_FBINFO(fbcon).fix.line_length : ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
p->next_plane = 0; p->next_plane = 0;
} }
...@@ -1040,7 +1040,7 @@ static int matrox_text_setfont(struct display* p, int width, int height) { ...@@ -1040,7 +1040,7 @@ static int matrox_text_setfont(struct display* p, int width, int height) {
MINFO_FROM_DISP(p); MINFO_FROM_DISP(p);
matrox_text_round(PMINFO &p->var, p); matrox_text_round(PMINFO &p->var, p);
p->next_line = p->line_length = ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep)); p->next_line = ACCESS_FBINFO(fbcon).fix.line_length = ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
if (p->conp) if (p->conp)
matrox_text_createcursor(PMINFO p); matrox_text_createcursor(PMINFO p);
...@@ -1144,11 +1144,11 @@ void initMatrox(WPMINFO struct display* p) { ...@@ -1144,11 +1144,11 @@ void initMatrox(WPMINFO struct display* p) {
if (p->dispsw && p->conp) if (p->dispsw && p->conp)
fb_con.con_cursor(p->conp, CM_ERASE); fb_con.con_cursor(p->conp, CM_ERASE);
p->dispsw_data = NULL; p->dispsw_data = NULL;
if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) { if ((ACCESS_FBINFO(fbcon).var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
if (p->type == FB_TYPE_TEXT) { if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
swtmp = &matroxfb_text; swtmp = &matroxfb_text;
} else { } else {
switch (p->var.bits_per_pixel) { switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB4 #ifdef FBCON_HAS_CFB4
case 4: case 4:
swtmp = &fbcon_cfb4; swtmp = &fbcon_cfb4;
...@@ -1183,10 +1183,10 @@ void initMatrox(WPMINFO struct display* p) { ...@@ -1183,10 +1183,10 @@ void initMatrox(WPMINFO struct display* p) {
} }
} }
dprintk(KERN_INFO "matroxfb: acceleration disabled\n"); dprintk(KERN_INFO "matroxfb: acceleration disabled\n");
} else if (p->type == FB_TYPE_TEXT) { } else if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
swtmp = &matroxfb_text; swtmp = &matroxfb_text;
} else { } else {
switch (p->var.bits_per_pixel) { switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB4 #ifdef FBCON_HAS_CFB4
case 4: case 4:
swtmp = &matroxfb_cfb4; swtmp = &matroxfb_cfb4;
...@@ -1222,8 +1222,8 @@ void initMatrox(WPMINFO struct display* p) { ...@@ -1222,8 +1222,8 @@ void initMatrox(WPMINFO struct display* p) {
} }
memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw))); memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw)));
p->dispsw = &ACCESS_FBINFO(dispsw); p->dispsw = &ACCESS_FBINFO(dispsw);
if ((p->type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) { if ((ACCESS_FBINFO(fbcon).fix.type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) {
ACCESS_FBINFO(hw_switch)->selhwcursor(PMINFO p); ACCESS_FBINFO(hw_switch)->selhwcursor(PMINFO2);
} }
} }
...@@ -1233,7 +1233,7 @@ void matrox_init_putc(WPMINFO struct display* p, void (*dac_createcursor)(WPMINF ...@@ -1233,7 +1233,7 @@ void matrox_init_putc(WPMINFO struct display* p, void (*dac_createcursor)(WPMINF
int i; int i;
if (p && p->conp) { if (p && p->conp) {
if (p->type == FB_TYPE_TEXT) { if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
matrox_text_createcursor(PMINFO p); matrox_text_createcursor(PMINFO p);
matrox_text_loadfont(PMINFO p); matrox_text_loadfont(PMINFO p);
i = 0; i = 0;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "matroxfb_base.h" #include "matroxfb_base.h"
void matrox_init_putc(WPMINFO struct display* p, void (*)(WPMINFO struct display *p)); void matrox_init_putc(WPMINFO struct display* p, void (*)(WPMINFO struct display *p));
void matrox_cfbX_init(WPMINFO struct display* p); void matrox_cfbX_init(WPMINFO2);
void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p); void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p);
void initMatrox(WPMINFO struct display* p); void initMatrox(WPMINFO struct display* p);
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
* *
* (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-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.65 2002/08/14
* *
* MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
* *
...@@ -77,6 +77,15 @@ ...@@ -77,6 +77,15 @@
* "Uns Lider" <unslider@miranda.org> * "Uns Lider" <unslider@miranda.org>
* G100 PLNWT fixes * G100 PLNWT fixes
* *
* "Denis Zaitsev" <zzz@cd-club.ru>
* Fixes
*
* "Mike Pieper" <mike@pieper-family.de>
* TVOut enhandcements, V4L2 control interface.
*
* "Diego Biurrun" <diego@biurrun.de>
* DFP testing
*
* (following author is not in any relation with this code, but his code * (following author is not in any relation with this code, but his code
* is included in this driver) * is included in this driver)
* *
...@@ -100,6 +109,7 @@ ...@@ -100,6 +109,7 @@
#include "matroxfb_Ti3026.h" #include "matroxfb_Ti3026.h"
#include "matroxfb_maven.h" #include "matroxfb_maven.h"
#include "matroxfb_crtc2.h" #include "matroxfb_crtc2.h"
#include "matroxfb_g450.h"
#include <linux/matroxfb.h> #include <linux/matroxfb.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -169,11 +179,13 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { ...@@ -169,11 +179,13 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
if (ACCESS_FBINFO(dead)) if (ACCESS_FBINFO(dead))
return; return;
ACCESS_FBINFO(fbcon).var.xoffset = var->xoffset;
ACCESS_FBINFO(fbcon).var.yoffset = var->yoffset;
disp = ACCESS_FBINFO(currcon_display); disp = ACCESS_FBINFO(currcon_display);
if (disp->type == FB_TYPE_TEXT) { if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
pos = var->yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(disp)?fontwidth(disp):8); pos = ACCESS_FBINFO(fbcon).var.yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + ACCESS_FBINFO(fbcon).var.xoffset / (fontwidth(disp)?fontwidth(disp):8);
} else { } else {
pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; pos = (ACCESS_FBINFO(fbcon).var.yoffset * ACCESS_FBINFO(fbcon).var.xres_virtual + ACCESS_FBINFO(fbcon).var.xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
pos += ACCESS_FBINFO(curr.ydstorg.chunks); pos += ACCESS_FBINFO(curr.ydstorg.chunks);
} }
p0 = ACCESS_FBINFO(hw).CRTC[0x0D] = pos & 0xFF; p0 = ACCESS_FBINFO(hw).CRTC[0x0D] = pos & 0xFF;
...@@ -212,6 +224,7 @@ static void matroxfb_remove(WPMINFO int dummy) { ...@@ -212,6 +224,7 @@ static void matroxfb_remove(WPMINFO int dummy) {
} }
matroxfb_unregister_device(MINFO); matroxfb_unregister_device(MINFO);
unregister_framebuffer(&ACCESS_FBINFO(fbcon)); unregister_framebuffer(&ACCESS_FBINFO(fbcon));
matroxfb_g450_shutdown(PMINFO2);
del_timer_sync(&ACCESS_FBINFO(cursor.timer)); del_timer_sync(&ACCESS_FBINFO(cursor.timer));
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
if (ACCESS_FBINFO(mtrr.vram_valid)) if (ACCESS_FBINFO(mtrr.vram_valid))
...@@ -233,7 +246,7 @@ static void matroxfb_remove(WPMINFO int dummy) { ...@@ -233,7 +246,7 @@ static void matroxfb_remove(WPMINFO int dummy) {
static int matroxfb_open(struct fb_info *info, int user) static int matroxfb_open(struct fb_info *info, int user)
{ {
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
DBG_LOOP("matroxfb_open") DBG_LOOP("matroxfb_open")
if (ACCESS_FBINFO(dead)) { if (ACCESS_FBINFO(dead)) {
...@@ -246,7 +259,7 @@ static int matroxfb_open(struct fb_info *info, int user) ...@@ -246,7 +259,7 @@ static int matroxfb_open(struct fb_info *info, int user)
static int matroxfb_release(struct fb_info *info, int user) static int matroxfb_release(struct fb_info *info, int user)
{ {
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
DBG_LOOP("matroxfb_release") DBG_LOOP("matroxfb_release")
if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) { if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) {
...@@ -258,7 +271,7 @@ static int matroxfb_release(struct fb_info *info, int user) ...@@ -258,7 +271,7 @@ static int matroxfb_release(struct fb_info *info, int user)
static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con, static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info* info) { struct fb_info* info) {
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
DBG("matroxfb_pan_display") DBG("matroxfb_pan_display")
...@@ -284,7 +297,7 @@ static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con, ...@@ -284,7 +297,7 @@ static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
static int matroxfb_updatevar(int con, struct fb_info *info) static int matroxfb_updatevar(int con, struct fb_info *info)
{ {
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
DBG("matroxfb_updatevar"); DBG("matroxfb_updatevar");
matrox_pan_var(PMINFO &fb_display[con].var); matrox_pan_var(PMINFO &fb_display[con].var);
...@@ -404,12 +417,43 @@ static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { ...@@ -404,12 +417,43 @@ static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
} }
static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) { static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) {
struct RGBT {
unsigned char bpp;
struct {
unsigned char offset,
length;
} red,
green,
blue,
transp;
signed char visual;
};
static const struct RGBT table[]= {
#if defined FBCON_HAS_VGATEXT
{ 0,{ 0,6},{0,6},{0,6},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
#endif
#if defined FBCON_HAS_CFB4 || defined FBCON_HAS_CFB8
{ 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
#endif
#if defined FBCON_HAS_CFB16
{15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR},
{16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR},
#endif
#if defined FBCON_HAS_CFB24
{24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR},
#endif
#if defined FBCON_HAS_CFB32
{32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR}
#endif
};
struct RGBT const *rgbt;
unsigned int bpp = var->bits_per_pixel;
unsigned int vramlen; unsigned int vramlen;
unsigned int memlen; unsigned int memlen;
DBG("matroxfb_decode_var") DBG("matroxfb_decode_var")
switch (var->bits_per_pixel) { switch (bpp) {
#ifdef FBCON_HAS_VGATEXT #ifdef FBCON_HAS_VGATEXT
case 0: if (!ACCESS_FBINFO(capable.text)) return -EINVAL; case 0: if (!ACCESS_FBINFO(capable.text)) return -EINVAL;
break; break;
...@@ -438,22 +482,22 @@ static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screenin ...@@ -438,22 +482,22 @@ static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screenin
var->yres_virtual = var->yres; var->yres_virtual = var->yres;
if (var->xres_virtual < var->xres) if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres; var->xres_virtual = var->xres;
if (var->bits_per_pixel) { if (bpp) {
var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel); var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp);
memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8; memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
if (memlen > vramlen) { if (memlen > vramlen) {
var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel); var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp);
memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8; memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
} }
/* There is hardware bug that no line can cross 4MB boundary */ /* There is hardware bug that no line can cross 4MB boundary */
/* give up for CFB24, it is impossible to easy workaround it */ /* give up for CFB24, it is impossible to easy workaround it */
/* for other try to do something */ /* for other try to do something */
if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) { if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) {
if (var->bits_per_pixel == 24) { if (bpp == 24) {
/* sorry */ /* sorry */
} else { } else {
unsigned int linelen; unsigned int linelen;
unsigned int m1 = linelen = var->xres_virtual * var->bits_per_pixel / 8; unsigned int m1 = linelen = var->xres_virtual * bpp / 8;
unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */ unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */
unsigned int max_yres; unsigned int max_yres;
...@@ -497,88 +541,27 @@ static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screenin ...@@ -497,88 +541,27 @@ static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screenin
if (var->yoffset + var->yres > var->yres_virtual) if (var->yoffset + var->yres > var->yres_virtual)
var->yoffset = var->yres_virtual - var->yres; var->yoffset = var->yres_virtual - var->yres;
if (var->bits_per_pixel == 0) { if (bpp == 16 && var->green.length == 5) {
var->red.offset = 0; bpp--; /* an artifical value - 15 */
var->red.length = 6;
var->green.offset = 0;
var->green.length = 6;
var->blue.offset = 0;
var->blue.length = 6;
var->transp.offset = 0;
var->transp.length = 0;
*visual = MX_VISUAL_PSEUDOCOLOR;
} else if (var->bits_per_pixel == 4) {
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
*visual = MX_VISUAL_PSEUDOCOLOR;
} else if (var->bits_per_pixel <= 8) {
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
*visual = MX_VISUAL_PSEUDOCOLOR;
} else {
if (var->bits_per_pixel <= 16) {
if (var->green.length == 5) {
var->red.offset = 10;
var->red.length = 5;
var->green.offset = 5;
var->green.length = 5;
var->blue.offset = 0;
var->blue.length = 5;
var->transp.offset = 15;
var->transp.length = 1;
} else {
var->red.offset = 11;
var->red.length = 5;
var->green.offset = 5;
var->green.length = 6;
var->blue.offset = 0;
var->blue.length = 5;
var->transp.offset = 0;
var->transp.length = 0;
}
} else if (var->bits_per_pixel <= 24) {
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
} else {
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->transp.offset = 24;
var->transp.length = 8;
}
dprintk("matroxfb: truecolor: "
"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
var->transp.length,
var->red.length,
var->green.length,
var->blue.length,
var->transp.offset,
var->red.offset,
var->green.offset,
var->blue.offset);
*visual = MX_VISUAL_DIRECTCOLOR;
} }
for (rgbt = table; rgbt->bpp < bpp; rgbt++);
#define SETCLR(clr)\
var->clr.offset = rgbt->clr.offset;\
var->clr.length = rgbt->clr.length
SETCLR(red);
SETCLR(green);
SETCLR(blue);
SETCLR(transp);
#undef SETCLR
*visual = rgbt->visual;
if (bpp > 8)
dprintk("matroxfb: truecolor: "
"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
var->transp.length, var->red.length, var->green.length, var->blue.length,
var->transp.offset, var->red.offset, var->green.offset, var->blue.offset);
*video_cmap_len = matroxfb_get_cmap_len(var); *video_cmap_len = matroxfb_get_cmap_len(var);
dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel, dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
var->xres_virtual, var->yres_virtual); var->xres_virtual, var->yres_virtual);
...@@ -589,9 +572,8 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, ...@@ -589,9 +572,8 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, unsigned blue, unsigned transp,
struct fb_info *fb_info) struct fb_info *fb_info)
{ {
struct display* p;
#ifdef CONFIG_FB_MATROX_MULTIHEAD #ifdef CONFIG_FB_MATROX_MULTIHEAD
struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info; struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon);
#endif #endif
DBG("matroxfb_setcolreg") DBG("matroxfb_setcolreg")
...@@ -611,18 +593,17 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, ...@@ -611,18 +593,17 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
ACCESS_FBINFO(palette[regno].blue) = blue; ACCESS_FBINFO(palette[regno].blue) = blue;
ACCESS_FBINFO(palette[regno].transp) = transp; ACCESS_FBINFO(palette[regno].transp) = transp;
p = ACCESS_FBINFO(currcon_display); if (ACCESS_FBINFO(fbcon).var.grayscale) {
if (p->var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */ /* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
} }
red = CNVT_TOHW(red, p->var.red.length); red = CNVT_TOHW(red, ACCESS_FBINFO(fbcon).var.red.length);
green = CNVT_TOHW(green, p->var.green.length); green = CNVT_TOHW(green, ACCESS_FBINFO(fbcon).var.green.length);
blue = CNVT_TOHW(blue, p->var.blue.length); blue = CNVT_TOHW(blue, ACCESS_FBINFO(fbcon).var.blue.length);
transp = CNVT_TOHW(transp, p->var.transp.length); transp = CNVT_TOHW(transp, ACCESS_FBINFO(fbcon).var.transp.length);
switch (p->var.bits_per_pixel) { switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_VGATEXT) #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_VGATEXT)
#ifdef FBCON_HAS_VGATEXT #ifdef FBCON_HAS_VGATEXT
case 0: case 0:
...@@ -642,87 +623,54 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, ...@@ -642,87 +623,54 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
#ifdef FBCON_HAS_CFB16 #ifdef FBCON_HAS_CFB16
case 16: case 16:
ACCESS_FBINFO(cmap.cfb16[regno]) = ACCESS_FBINFO(cmap.cfb16[regno]) =
(red << p->var.red.offset) | (red << ACCESS_FBINFO(fbcon).var.red.offset) |
(green << p->var.green.offset) | (green << ACCESS_FBINFO(fbcon).var.green.offset) |
(blue << p->var.blue.offset) | (blue << ACCESS_FBINFO(fbcon).var.blue.offset) |
(transp << p->var.transp.offset); /* for 1:5:5:5 */ (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* for 1:5:5:5 */
break; break;
#endif #endif
#ifdef FBCON_HAS_CFB24 #ifdef FBCON_HAS_CFB24
case 24: case 24:
ACCESS_FBINFO(cmap.cfb24[regno]) = ACCESS_FBINFO(cmap.cfb24[regno]) =
(red << p->var.red.offset) | (red << ACCESS_FBINFO(fbcon).var.red.offset) |
(green << p->var.green.offset) | (green << ACCESS_FBINFO(fbcon).var.green.offset) |
(blue << p->var.blue.offset); (blue << ACCESS_FBINFO(fbcon).var.blue.offset);
break; break;
#endif #endif
#ifdef FBCON_HAS_CFB32 #ifdef FBCON_HAS_CFB32
case 32: case 32:
ACCESS_FBINFO(cmap.cfb32[regno]) = ACCESS_FBINFO(cmap.cfb32[regno]) =
(red << p->var.red.offset) | (red << ACCESS_FBINFO(fbcon).var.red.offset) |
(green << p->var.green.offset) | (green << ACCESS_FBINFO(fbcon).var.green.offset) |
(blue << p->var.blue.offset) | (blue << ACCESS_FBINFO(fbcon).var.blue.offset) |
(transp << p->var.transp.offset); /* 8:8:8:8 */ (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* 8:8:8:8 */
break; break;
#endif #endif
} }
return 0; return 0;
} }
static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con, static void matroxfb_update_fix(WPMINFO2)
struct fb_info *info)
{ {
struct display* p; struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
DBG("matroxfb_get_fix") DBG("matroxfb_get_fix")
#define minfo ((struct matrox_fb_info*)info)
if (ACCESS_FBINFO(dead)) {
return -ENXIO;
}
if (con >= 0)
p = fb_display + con;
else
p = ACCESS_FBINFO(fbcon.disp);
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id,"MATROX"); strcpy(fix->id,"MATROX");
fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
fix->type = p->type; fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
fix->type_aux = p->type_aux;
fix->visual = p->visual;
fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
fix->ypanstep = 1; fix->ypanstep = 1;
fix->ywrapstep = 0; fix->ywrapstep = 0;
fix->line_length = p->line_length;
fix->mmio_start = ACCESS_FBINFO(mmio.base); fix->mmio_start = ACCESS_FBINFO(mmio.base);
fix->mmio_len = ACCESS_FBINFO(mmio.len); fix->mmio_len = ACCESS_FBINFO(mmio.len);
fix->accel = ACCESS_FBINFO(devflags.accelerator); fix->accel = ACCESS_FBINFO(devflags.accelerator);
return 0;
#undef minfo
}
static int matroxfb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
#define minfo ((struct matrox_fb_info*)info)
DBG("matroxfb_get_var")
if(con < 0)
*var=ACCESS_FBINFO(fbcon.disp)->var;
else
*var=fb_display[con].var;
return 0;
#undef minfo
} }
static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info) struct fb_info *info)
{ {
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
int err; int err;
int visual; int visual;
int cmap_len; int cmap_len;
...@@ -763,17 +711,19 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, ...@@ -763,17 +711,19 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
display->var = *var; display->var = *var;
/* cmap */ /* cmap */
ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg; ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
display->visual = visual; if (display == ACCESS_FBINFO(currcon_display)) {
display->ypanstep = 1; ACCESS_FBINFO(fbcon).var = *var;
display->ywrapstep = 0; matroxfb_update_fix(PMINFO2);
if (var->bits_per_pixel) { ACCESS_FBINFO(fbcon).fix.visual = visual;
display->type = FB_TYPE_PACKED_PIXELS; if (var->bits_per_pixel) {
display->type_aux = 0; ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_PACKED_PIXELS;
display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; ACCESS_FBINFO(fbcon).fix.type_aux = 0;
} else { display->next_line = ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
display->type = FB_TYPE_TEXT; } else {
display->type_aux = ACCESS_FBINFO(devflags.text_type_aux); ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_TEXT;
display->next_line = display->line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep); ACCESS_FBINFO(fbcon).fix.type_aux = ACCESS_FBINFO(devflags.text_type_aux);
display->next_line = ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep);
}
} }
display->can_soft_blank = 1; display->can_soft_blank = 1;
display->inverse = ACCESS_FBINFO(devflags.inverse); display->inverse = ACCESS_FBINFO(devflags.inverse);
...@@ -788,7 +738,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, ...@@ -788,7 +738,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
unsigned int pos; unsigned int pos;
ACCESS_FBINFO(curr.cmap_len) = cmap_len; ACCESS_FBINFO(curr.cmap_len) = cmap_len;
if (display->type == FB_TYPE_TEXT) { if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
/* textmode must be in first megabyte, so no ydstorg allowed */ /* textmode must be in first megabyte, so no ydstorg allowed */
ACCESS_FBINFO(curr.ydstorg.bytes) = 0; ACCESS_FBINFO(curr.ydstorg.bytes) = 0;
ACCESS_FBINFO(curr.ydstorg.chunks) = 0; ACCESS_FBINFO(curr.ydstorg.chunks) = 0;
...@@ -818,8 +768,10 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, ...@@ -818,8 +768,10 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
{ struct my_timming mt; { struct my_timming mt;
struct matrox_hw_state* hw; struct matrox_hw_state* hw;
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;
...@@ -834,8 +786,18 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, ...@@ -834,8 +786,18 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
del_timer_sync(&ACCESS_FBINFO(cursor.timer)); del_timer_sync(&ACCESS_FBINFO(cursor.timer));
ACCESS_FBINFO(cursor.state) = CM_ERASE; ACCESS_FBINFO(cursor.state) = CM_ERASE;
down_read(&ACCESS_FBINFO(altout).lock);
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
ACCESS_FBINFO(outputs[out]).output->compute) {
ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
}
}
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 (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
if (fontheight(display)) if (fontheight(display))
pos = var->yoffset / fontheight(display) * display->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(display)?fontwidth(display):8); pos = var->yoffset / fontheight(display) * display->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(display)?fontwidth(display):8);
else else
...@@ -849,39 +811,23 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, ...@@ -849,39 +811,23 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
hw->CRTC[0x0C] = (pos & 0xFF00) >> 8; hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
hw->CRTCEXT[8] = pos >> 21; hw->CRTCEXT[8] = pos >> 21;
if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
if (ACCESS_FBINFO(primout))
ACCESS_FBINFO(primout)->compute(MINFO, &mt);
}
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
down_read(&ACCESS_FBINFO(altout.lock));
if (ACCESS_FBINFO(altout.output))
ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt);
up_read(&ACCESS_FBINFO(altout.lock));
}
ACCESS_FBINFO(hw_switch->restore(PMINFO display)); ACCESS_FBINFO(hw_switch->restore(PMINFO display));
if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) { down_read(&ACCESS_FBINFO(altout).lock);
if (ACCESS_FBINFO(primout)) for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
ACCESS_FBINFO(primout)->program(MINFO); if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
} ACCESS_FBINFO(outputs[out]).output->program) {
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
down_read(&ACCESS_FBINFO(altout.lock)); }
if (ACCESS_FBINFO(altout.output))
ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device));
up_read(&ACCESS_FBINFO(altout.lock));
} }
ACCESS_FBINFO(cursor.redraw) = 1; ACCESS_FBINFO(cursor.redraw) = 1;
if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) { for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (ACCESS_FBINFO(primout)) if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
ACCESS_FBINFO(primout)->start(MINFO); ACCESS_FBINFO(outputs[out]).output->start) {
} ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { }
down_read(&ACCESS_FBINFO(altout.lock));
if (ACCESS_FBINFO(altout.output))
ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
up_read(&ACCESS_FBINFO(altout.lock));
} }
matrox_cfbX_init(PMINFO display); up_read(&ACCESS_FBINFO(altout).lock);
matrox_cfbX_init(PMINFO2);
my_install_cmap(PMINFO2); my_install_cmap(PMINFO2);
} }
} }
...@@ -896,7 +842,7 @@ static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green, ...@@ -896,7 +842,7 @@ static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green,
DBG("matrox_getcolreg") DBG("matrox_getcolreg")
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
/* /*
* Read a single color register and split it into colors/transparent. * Read a single color register and split it into colors/transparent.
* Return != 0 for invalid regno. * Return != 0 for invalid regno.
...@@ -916,7 +862,7 @@ static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green, ...@@ -916,7 +862,7 @@ static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green,
static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info) struct fb_info *info)
{ {
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp) struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp)
: fb_display + con; : fb_display + con;
...@@ -942,7 +888,7 @@ static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, ...@@ -942,7 +888,7 @@ static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
{ {
unsigned int cmap_len; unsigned int cmap_len;
struct display* dsp = (con < 0) ? info->disp : (fb_display + con); struct display* dsp = (con < 0) ? info->disp : (fb_display + con);
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
DBG("matroxfb_set_cmap") DBG("matroxfb_set_cmap")
...@@ -982,18 +928,22 @@ static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank) ...@@ -982,18 +928,22 @@ static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank)
vblank->flags |= FB_VBLANK_HBLANKING; vblank->flags |= FB_VBLANK_HBLANKING;
if (sts1 & 8) if (sts1 & 8)
vblank->flags |= FB_VBLANK_VSYNCING; vblank->flags |= FB_VBLANK_VSYNCING;
if (vblank->vcount >= ACCESS_FBINFO(currcon_display)->var.yres) if (vblank->vcount >= ACCESS_FBINFO(fbcon).var.yres)
vblank->flags |= FB_VBLANK_VBLANKING; vblank->flags |= FB_VBLANK_VBLANKING;
vblank->hcount = 0; vblank->hcount = 0;
vblank->count = 0; vblank->count = 0;
return 0; return 0;
} }
static struct matrox_altout panellink_output = {
.name = "Panellink output",
};
static int matroxfb_ioctl(struct inode *inode, struct file *file, static int matroxfb_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg, int con, unsigned int cmd, unsigned long arg, int con,
struct fb_info *info) struct fb_info *info)
{ {
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
DBG("matroxfb_ioctl") DBG("matroxfb_ioctl")
if (ACCESS_FBINFO(dead)) { if (ACCESS_FBINFO(dead)) {
...@@ -1016,80 +966,74 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file, ...@@ -1016,80 +966,74 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
case MATROXFB_SET_OUTPUT_MODE: case MATROXFB_SET_OUTPUT_MODE:
{ {
struct matroxioc_output_mode mom; struct matroxioc_output_mode mom;
struct matrox_altout *oproc;
int val; int val;
if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom))) if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
return -EFAULT; return -EFAULT;
if (mom.output >= sizeof(u_int32_t)) if (mom.output >= MATROXFB_MAX_OUTPUTS)
return -EINVAL; return -ENXIO;
switch (mom.output) { down_read(&ACCESS_FBINFO(altout.lock));
case MATROXFB_OUTPUT_PRIMARY: oproc = ACCESS_FBINFO(outputs[mom.output]).output;
if (mom.mode != MATROXFB_OUTPUT_MODE_MONITOR) if (!oproc) {
return -EINVAL; val = -ENXIO;
/* mode did not change... */ } else if (!oproc->verifymode) {
return 0; if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
case MATROXFB_OUTPUT_SECONDARY: val = 0;
} else {
val = -EINVAL; val = -EINVAL;
down_read(&ACCESS_FBINFO(altout.lock)); }
if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device)) } else {
val = ACCESS_FBINFO(altout.output)->setmode(ACCESS_FBINFO(altout.device), mom.mode); val = oproc->verifymode(ACCESS_FBINFO(outputs[mom.output]).data, mom.mode);
up_read(&ACCESS_FBINFO(altout.lock)); }
if (val != 1) if (!val) {
return val; if (ACCESS_FBINFO(outputs[mom.output]).mode != mom.mode) {
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) ACCESS_FBINFO(outputs[mom.output]).mode = mom.mode;
matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info); val = 1;
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { }
}
up_read(&ACCESS_FBINFO(altout.lock));
if (val != 1)
return val;
switch (ACCESS_FBINFO(outputs[mom.output]).src) {
case MATROXFB_SRC_CRTC1:
matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info);
break;
case MATROXFB_SRC_CRTC2:
{
struct matroxfb_dh_fb_info* crtc2; struct matroxfb_dh_fb_info* crtc2;
down_read(&ACCESS_FBINFO(crtc2.lock)); down_read(&ACCESS_FBINFO(crtc2.lock));
crtc2 = (struct matroxfb_dh_fb_info*)(ACCESS_FBINFO(crtc2.info)); crtc2 = ACCESS_FBINFO(crtc2.info);
if (crtc2) if (crtc2)
crtc2->fbcon.switch_con(crtc2->currcon, &crtc2->fbcon); crtc2->fbcon.switch_con(crtc2->fbcon.currcon, &crtc2->fbcon);
up_read(&ACCESS_FBINFO(crtc2.lock)); up_read(&ACCESS_FBINFO(crtc2.lock));
} }
return 0; break;
case MATROXFB_OUTPUT_DFP:
if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
return -ENXIO;
if (mom.mode!= MATROXFB_OUTPUT_MODE_MONITOR)
return -EINVAL;
/* mode did not change... */
return 0;
default:
return -EINVAL;
} }
return 0; return 0;
} }
case MATROXFB_GET_OUTPUT_MODE: case MATROXFB_GET_OUTPUT_MODE:
{ {
struct matroxioc_output_mode mom; struct matroxioc_output_mode mom;
struct matrox_altout *oproc;
int val; int val;
if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom))) if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
return -EFAULT; return -EFAULT;
if (mom.output >= sizeof(u_int32_t)) if (mom.output >= MATROXFB_MAX_OUTPUTS)
return -EINVAL; return -ENXIO;
switch (mom.output) { down_read(&ACCESS_FBINFO(altout.lock));
case MATROXFB_OUTPUT_PRIMARY: oproc = ACCESS_FBINFO(outputs[mom.output]).output;
mom.mode = MATROXFB_OUTPUT_MODE_MONITOR; if (!oproc) {
break; val = -ENXIO;
case MATROXFB_OUTPUT_SECONDARY: } else {
val = -EINVAL; mom.mode = ACCESS_FBINFO(outputs[mom.output]).mode;
down_read(&ACCESS_FBINFO(altout.lock)); val = 0;
if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device))
val = ACCESS_FBINFO(altout.output)->getmode(ACCESS_FBINFO(altout.device), &mom.mode);
up_read(&ACCESS_FBINFO(altout.lock));
if (val)
return val;
break;
case MATROXFB_OUTPUT_DFP:
if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
return -ENXIO;
mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
break;
default:
return -EINVAL;
} }
up_read(&ACCESS_FBINFO(altout.lock));
if (val)
return val;
if (copy_to_user((struct matroxioc_output_mode*)arg, &mom, sizeof(mom))) if (copy_to_user((struct matroxioc_output_mode*)arg, &mom, sizeof(mom)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -1097,52 +1041,109 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file, ...@@ -1097,52 +1041,109 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
case MATROXFB_SET_OUTPUT_CONNECTION: case MATROXFB_SET_OUTPUT_CONNECTION:
{ {
u_int32_t tmp; u_int32_t tmp;
int i;
int changes;
if (copy_from_user(&tmp, (u_int32_t*)arg, sizeof(tmp))) if (copy_from_user(&tmp, (u_int32_t*)arg, sizeof(tmp)))
return -EFAULT; return -EFAULT;
if (tmp & ~ACCESS_FBINFO(output.all)) for (i = 0; i < 32; i++) {
return -EINVAL; if (tmp & (1 << i)) {
if (tmp & ACCESS_FBINFO(output.sh)) if (i >= MATROXFB_MAX_OUTPUTS)
return -EINVAL; return -ENXIO;
if (tmp & MATROXFB_OUTPUT_CONN_DFP) { if (!ACCESS_FBINFO(outputs[i]).output)
if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY) return -ENXIO;
return -EINVAL; switch (ACCESS_FBINFO(outputs[i]).src) {
if (ACCESS_FBINFO(output.sh)) case MATROXFB_SRC_NONE:
return -EINVAL; case MATROXFB_SRC_CRTC1:
break;
default:
return -EBUSY;
}
}
} }
if (tmp == ACCESS_FBINFO(output.ph)) if (ACCESS_FBINFO(devflags.panellink)) {
if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
return -EINVAL;
for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC2) {
return -EBUSY;
}
}
}
}
changes = 0;
for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
if (tmp & (1 << i)) {
if (ACCESS_FBINFO(outputs[i]).src != MATROXFB_SRC_CRTC1) {
changes = 1;
ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_CRTC1;
}
} else if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
changes = 1;
ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_NONE;
}
}
if (!changes)
return 0; return 0;
ACCESS_FBINFO(output.ph) = tmp;
matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info); matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info);
return 0; return 0;
} }
case MATROXFB_GET_OUTPUT_CONNECTION: case MATROXFB_GET_OUTPUT_CONNECTION:
{ {
if (put_user(ACCESS_FBINFO(output.ph), (u_int32_t*)arg)) u_int32_t conn = 0;
int i;
for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
conn |= 1 << i;
}
}
if (put_user(conn, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case MATROXFB_GET_AVAILABLE_OUTPUTS: case MATROXFB_GET_AVAILABLE_OUTPUTS:
{ {
u_int32_t tmp; u_int32_t conn = 0;
int i;
tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.sh);
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
tmp &= ~MATROXFB_OUTPUT_CONN_SECONDARY; if (ACCESS_FBINFO(outputs[i]).output) {
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) switch (ACCESS_FBINFO(outputs[i]).src) {
tmp &= ~MATROXFB_OUTPUT_CONN_DFP; case MATROXFB_SRC_NONE:
if (put_user(tmp, (u_int32_t*)arg)) case MATROXFB_SRC_CRTC1:
conn |= 1 << i;
break;
}
}
}
if (ACCESS_FBINFO(devflags.panellink)) {
if (conn & MATROXFB_OUTPUT_CONN_DFP)
conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
if (conn & MATROXFB_OUTPUT_CONN_SECONDARY)
conn &= ~MATROXFB_OUTPUT_CONN_DFP;
}
if (put_user(conn, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case MATROXFB_GET_ALL_OUTPUTS: case MATROXFB_GET_ALL_OUTPUTS:
{ {
if (put_user(ACCESS_FBINFO(output.all), (u_int32_t*)arg)) u_int32_t conn = 0;
int i;
for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
if (ACCESS_FBINFO(outputs[i]).output) {
conn |= 1 << i;
}
}
if (put_user(conn, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
} }
return -EINVAL; return -ENOTTY;
#undef minfo #undef minfo
} }
...@@ -1150,7 +1151,7 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file, ...@@ -1150,7 +1151,7 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
static int matroxfb_blank(int blank, struct fb_info *info) static int matroxfb_blank(int blank, struct fb_info *info)
{ {
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
int seq; int seq;
int crtc; int crtc;
CRITFLAGS CRITFLAGS
...@@ -1184,8 +1185,6 @@ static struct fb_ops matroxfb_ops = { ...@@ -1184,8 +1185,6 @@ static struct fb_ops matroxfb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_open = matroxfb_open, .fb_open = matroxfb_open,
.fb_release = matroxfb_release, .fb_release = matroxfb_release,
.fb_get_fix = matroxfb_get_fix,
.fb_get_var = matroxfb_get_var,
.fb_set_var = matroxfb_set_var, .fb_set_var = matroxfb_set_var,
.fb_get_cmap = matroxfb_get_cmap, .fb_get_cmap = matroxfb_get_cmap,
.fb_set_cmap = matroxfb_set_cmap, .fb_set_cmap = matroxfb_set_cmap,
...@@ -1197,7 +1196,7 @@ static struct fb_ops matroxfb_ops = { ...@@ -1197,7 +1196,7 @@ static struct fb_ops matroxfb_ops = {
int matroxfb_switch(int con, struct fb_info *info) int matroxfb_switch(int con, struct fb_info *info)
{ {
#define minfo ((struct matrox_fb_info*)info) #define minfo (container_of(info, struct matrox_fb_info, fbcon))
struct fb_cmap* cmap; struct fb_cmap* cmap;
struct display *p; struct display *p;
...@@ -1392,10 +1391,10 @@ static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4 ...@@ -1392,10 +1391,10 @@ static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4
#define DEVF_VIDEO64BIT 0x0001 #define DEVF_VIDEO64BIT 0x0001
#define DEVF_SWAPS 0x0002 #define DEVF_SWAPS 0x0002
#define DEVF_SRCORG 0x0004 #define DEVF_SRCORG 0x0004
#define DEVF_BOTHDACS 0x0008 /* put CRTC1 on both outputs by default */ #define DEVF_DUALHEAD 0x0008
#define DEVF_CROSS4MB 0x0010 #define DEVF_CROSS4MB 0x0010
#define DEVF_TEXT4B 0x0020 #define DEVF_TEXT4B 0x0020
#define DEVF_DDC_8_2 0x0040 /* #define DEVF_recycled 0x0040 */
/* #define DEVF_recycled 0x0080 */ /* #define DEVF_recycled 0x0080 */
#define DEVF_SUPPORT32MB 0x0100 #define DEVF_SUPPORT32MB 0x0100
#define DEVF_ANY_VXRES 0x0200 #define DEVF_ANY_VXRES 0x0200
...@@ -1405,14 +1404,14 @@ static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4 ...@@ -1405,14 +1404,14 @@ static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4
#define DEVF_PANELLINK_CAPABLE 0x2000 #define DEVF_PANELLINK_CAPABLE 0x2000
#define DEVF_G450DAC 0x4000 #define DEVF_G450DAC 0x4000
#define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2) #define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB)
#define DEVF_G2CORE (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG) #define DEVF_G2CORE (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG | DEVF_DUALHEAD)
#define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */ #define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */
#define DEVF_G200 (DEVF_G2CORE) #define DEVF_G200 (DEVF_G2CORE)
#define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2) #define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
/* if you'll find how to drive DFP... */ /* if you'll find how to drive DFP... */
#define DEVF_G450 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG) #define DEVF_G450 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD)
#define DEVF_G550 (DEVF_G450 | DEVF_BOTHDACS) #define DEVF_G550 (DEVF_G450)
static struct board { static struct board {
unsigned short vendor, device, rev, svid, sid; unsigned short vendor, device, rev, svid, sid;
...@@ -1606,27 +1605,24 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){ ...@@ -1606,27 +1605,24 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){
ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8; ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
} }
#ifdef CONFIG_FB_MATROX_32MB #ifdef CONFIG_FB_MATROX_32MB
ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB; ACCESS_FBINFO(devflags.support32MB) = (b->flags & DEVF_SUPPORT32MB) != 0;
#endif #endif
ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES); ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
ACCESS_FBINFO(devflags.crtc2) = b->flags & DEVF_CRTC2; ACCESS_FBINFO(devflags.crtc2) = (b->flags & DEVF_CRTC2) != 0;
ACCESS_FBINFO(devflags.maven_capable) = b->flags & DEVF_MAVEN_CAPABLE; ACCESS_FBINFO(devflags.maven_capable) = (b->flags & DEVF_MAVEN_CAPABLE) != 0;
ACCESS_FBINFO(devflags.dualhead) = (b->flags & DEVF_DUALHEAD) != 0;
if (b->flags & DEVF_PANELLINK_CAPABLE) { if (b->flags & DEVF_PANELLINK_CAPABLE) {
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_DFP; ACCESS_FBINFO(outputs[2]).data = MINFO;
ACCESS_FBINFO(outputs[2]).output = &panellink_output;
if (dfp) if (dfp)
ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_DFP; ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
} else
if (b->flags & DEVF_BOTHDACS) { ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
#ifdef CONFIG_FB_MATROX_G450 ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY; ACCESS_FBINFO(devflags.panellink) = 1;
ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_SECONDARY;
#else
printk(KERN_INFO "Only digital output of G550 is now working (in analog mode). Enable G450 support in\n");
printk(KERN_INFO "kernel configuration if you have analog monitor connected to G550 analog output.\n");
#endif
} }
ACCESS_FBINFO(devflags.dfp_type) = dfp_type; ACCESS_FBINFO(devflags.dfp_type) = dfp_type;
ACCESS_FBINFO(devflags.g450dac) = b->flags & DEVF_G450DAC; ACCESS_FBINFO(devflags.g450dac) = (b->flags & DEVF_G450DAC) != 0;
ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode); ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode); ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
...@@ -1732,6 +1728,7 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){ ...@@ -1732,6 +1728,7 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){
if (!ACCESS_FBINFO(devflags.novga)) if (!ACCESS_FBINFO(devflags.novga))
request_region(0x3C0, 32, "matrox"); request_region(0x3C0, 32, "matrox");
matroxfb_g450_connect(PMINFO2);
ACCESS_FBINFO(hw_switch->reset(PMINFO2)); ACCESS_FBINFO(hw_switch->reset(PMINFO2));
ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0; ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
...@@ -1885,6 +1882,7 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){ ...@@ -1885,6 +1882,7 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){
} }
return 0; return 0;
failVideoIO:; failVideoIO:;
matroxfb_g450_shutdown(PMINFO2);
mga_iounmap(ACCESS_FBINFO(video.vbase)); mga_iounmap(ACCESS_FBINFO(video.vbase));
failCtrlIO:; failCtrlIO:;
mga_iounmap(ACCESS_FBINFO(mmio.vbase)); mga_iounmap(ACCESS_FBINFO(mmio.vbase));
...@@ -2072,10 +2070,6 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm ...@@ -2072,10 +2070,6 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
init_rwsem(&ACCESS_FBINFO(crtc2.lock)); init_rwsem(&ACCESS_FBINFO(crtc2.lock));
init_rwsem(&ACCESS_FBINFO(altout.lock)); init_rwsem(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(output.all) = MATROXFB_OUTPUT_CONN_PRIMARY;
ACCESS_FBINFO(output.ph) = MATROXFB_OUTPUT_CONN_PRIMARY;
ACCESS_FBINFO(output.sh) = 0;
err = initMatrox2(PMINFO d, b); err = initMatrox2(PMINFO d, b);
if (!err) { if (!err) {
#ifndef CONFIG_FB_MATROX_MULTIHEAD #ifndef CONFIG_FB_MATROX_MULTIHEAD
...@@ -2489,8 +2483,8 @@ int __init matroxfb_init(void) ...@@ -2489,8 +2483,8 @@ int __init matroxfb_init(void)
/* *************************** init module code **************************** */ /* *************************** init module code **************************** */
MODULE_AUTHOR("(c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450"); MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_PARM(mem, "i"); MODULE_PARM(mem, "i");
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450
* *
* (c) 1998,1999,2000,2001 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
* *
*/ */
#ifndef __MATROXFB_H__ #ifndef __MATROXFB_H__
...@@ -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 {
...@@ -396,15 +399,17 @@ struct matrox_accel_data { ...@@ -396,15 +399,17 @@ struct matrox_accel_data {
}; };
struct matrox_altout { struct matrox_altout {
const char *name;
int (*compute)(void* altout_dev, struct my_timming* input); int (*compute)(void* altout_dev, struct my_timming* input);
int (*program)(void* altout_dev); int (*program)(void* altout_dev);
int (*start)(void* altout_dev); int (*start)(void* altout_dev);
void (*incuse)(void* altout_dev); int (*verifymode)(void* altout_dev, u_int32_t mode);
void (*decuse)(void* altout_dev);
int (*setmode)(void* altout_dev, u_int32_t mode);
int (*getmode)(void* altout_dev, u_int32_t* mode);
}; };
#define MATROXFB_SRC_NONE 0
#define MATROXFB_SRC_CRTC1 1
#define MATROXFB_SRC_CRTC2 2
enum mga_chip { MGA_2064, MGA_2164, MGA_1064, MGA_1164, MGA_G100, MGA_G200, MGA_G400, MGA_G450, MGA_G550 }; enum mga_chip { MGA_2064, MGA_2164, MGA_1064, MGA_1164, MGA_G100, MGA_G200, MGA_G400, MGA_G450, MGA_G550 };
struct matrox_bios { struct matrox_bios {
...@@ -421,9 +426,9 @@ struct matrox_bios { ...@@ -421,9 +426,9 @@ struct matrox_bios {
struct matrox_switch; struct matrox_switch;
struct matroxfb_driver; struct matroxfb_driver;
struct matroxfb_dh_fb_info;
struct matrox_fb_info { struct matrox_fb_info {
/* fb_info must be first */
struct fb_info fbcon; struct fb_info fbcon;
struct list_head next_fb; struct list_head next_fb;
...@@ -439,20 +444,25 @@ struct matrox_fb_info { ...@@ -439,20 +444,25 @@ struct matrox_fb_info {
struct pci_dev* pcidev; struct pci_dev* pcidev;
struct { struct {
u_int32_t all; unsigned int pixclock;
u_int32_t ph; int mnp;
u_int32_t sh; } crtc1;
} output;
struct matrox_altout* primout;
struct { struct {
struct fb_info* info; unsigned int pixclock;
int mnp;
struct matroxfb_dh_fb_info* info;
struct rw_semaphore lock; struct rw_semaphore lock;
} crtc2; } crtc2;
struct { struct {
struct matrox_altout* output; struct rw_semaphore lock;
void* device;
struct rw_semaphore lock;
} altout; } altout;
#define MATROXFB_MAX_OUTPUTS 3
struct {
unsigned int src;
struct matrox_altout* output;
void* data;
unsigned int mode;
} outputs[MATROXFB_MAX_OUTPUTS];
#define MATROXFB_MAX_FB_DRIVERS 5 #define MATROXFB_MAX_FB_DRIVERS 5
struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]); struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]);
...@@ -541,6 +551,8 @@ struct matrox_fb_info { ...@@ -541,6 +551,8 @@ struct matrox_fb_info {
int memtype; int memtype;
int g450dac; int g450dac;
int dfp_type; int dfp_type;
int panellink; /* G400 DFP possible (not G450/G550) */
int dualhead;
unsigned int fbResource; unsigned int fbResource;
} devflags; } devflags;
struct display_switch dispsw; struct display_switch dispsw;
...@@ -618,7 +630,7 @@ struct matrox_fb_info { ...@@ -618,7 +630,7 @@ struct matrox_fb_info {
#define PMINFO PMINFO2 , #define PMINFO PMINFO2 ,
static inline struct matrox_fb_info* mxinfo(const struct display* p) { static inline struct matrox_fb_info* mxinfo(const struct display* p) {
return (struct matrox_fb_info*)p->fb_info; return container_of(p->fb_info, struct matrox_fb_info, fbcon);
} }
#define PMXINFO(p) mxinfo(p), #define PMXINFO(p) mxinfo(p),
...@@ -658,7 +670,7 @@ struct matrox_switch { ...@@ -658,7 +670,7 @@ struct matrox_switch {
void (*reset)(WPMINFO2); void (*reset)(WPMINFO2);
int (*init)(WPMINFO struct my_timming*, struct display*); int (*init)(WPMINFO struct my_timming*, struct display*);
void (*restore)(WPMINFO struct display*); void (*restore)(WPMINFO struct display*);
int (*selhwcursor)(WPMINFO struct display*); int (*selhwcursor)(WPMINFO2);
}; };
struct matroxfb_driver { struct matroxfb_driver {
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
* *
* (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-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.65 2002/08/14
* *
*/ */
...@@ -28,7 +28,7 @@ MODULE_PARM_DESC(mem, "Memory size reserved for dualhead (default=8MB)"); ...@@ -28,7 +28,7 @@ MODULE_PARM_DESC(mem, "Memory size reserved for dualhead (default=8MB)");
static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green, static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
unsigned *blue, unsigned *transp, struct fb_info* info) { unsigned *blue, unsigned *transp, struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
if (regno >= 16) if (regno >= 16)
return 1; return 1;
*red = m2info->palette[regno].red; *red = m2info->palette[regno].red;
...@@ -41,8 +41,7 @@ static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green, ...@@ -41,8 +41,7 @@ static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green, static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info* info) { unsigned blue, unsigned transp, struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
struct display* p;
if (regno >= 16) if (regno >= 16)
return 1; return 1;
...@@ -50,33 +49,32 @@ static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green, ...@@ -50,33 +49,32 @@ static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
m2info->palette[regno].blue = blue; m2info->palette[regno].blue = blue;
m2info->palette[regno].green = green; m2info->palette[regno].green = green;
m2info->palette[regno].transp = transp; m2info->palette[regno].transp = transp;
p = m2info->currcon_display; if (m2info->fbcon.var.grayscale) {
if (p->var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */ /* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
} }
red = CNVT_TOHW(red, p->var.red.length); red = CNVT_TOHW(red, m2info->fbcon.var.red.length);
green = CNVT_TOHW(green, p->var.green.length); green = CNVT_TOHW(green, m2info->fbcon.var.green.length);
blue = CNVT_TOHW(blue, p->var.blue.length); blue = CNVT_TOHW(blue, m2info->fbcon.var.blue.length);
transp = CNVT_TOHW(transp, p->var.transp.length); transp = CNVT_TOHW(transp, m2info->fbcon.var.transp.length);
switch (p->var.bits_per_pixel) { switch (m2info->fbcon.var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB16 #ifdef FBCON_HAS_CFB16
case 16: case 16:
m2info->cmap.cfb16[regno] = m2info->cmap.cfb16[regno] =
(red << p->var.red.offset) | (red << m2info->fbcon.var.red.offset) |
(green << p->var.green.offset) | (green << m2info->fbcon.var.green.offset) |
(blue << p->var.blue.offset) | (blue << m2info->fbcon.var.blue.offset) |
(transp << p->var.transp.offset); (transp << m2info->fbcon.var.transp.offset);
break; break;
#endif #endif
#ifdef FBCON_HAS_CFB32 #ifdef FBCON_HAS_CFB32
case 32: case 32:
m2info->cmap.cfb32[regno] = m2info->cmap.cfb32[regno] =
(red << p->var.red.offset) | (red << m2info->fbcon.var.red.offset) |
(green << p->var.green.offset) | (green << m2info->fbcon.var.green.offset) |
(blue << p->var.blue.offset) | (blue << m2info->fbcon.var.blue.offset) |
(transp << p->var.transp.offset); (transp << m2info->fbcon.var.transp.offset);
break; break;
#endif #endif
} }
...@@ -99,10 +97,10 @@ static inline void my_install_cmap(struct matroxfb_dh_fb_info* m2info) ...@@ -99,10 +97,10 @@ static inline void my_install_cmap(struct matroxfb_dh_fb_info* m2info)
static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
struct my_timming* mt, struct my_timming* mt,
struct display* p,
int mode, int mode,
unsigned int pos) { unsigned int pos) {
u_int32_t tmp; u_int32_t tmp;
u_int32_t datactl;
MINFO_FROM(m2info->primary_dev); MINFO_FROM(m2info->primary_dev);
switch (mode) { switch (mode) {
...@@ -117,26 +115,26 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, ...@@ -117,26 +115,26 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
tmp = 0x00800000; tmp = 0x00800000;
break; break;
} }
tmp |= 0x00000001; /* enable CRTC2 */
if (ACCESS_FBINFO(output.sh)) { datactl = 0;
tmp |= 0x00000001; /* enable CRTC2 */ if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
if (ACCESS_FBINFO(devflags.g450dac)) {
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { tmp |= 0x00000006; /* source from secondary pixel PLL */
if (ACCESS_FBINFO(devflags.g450dac)) { /* no vidrst when in monitor mode */
tmp |= 0x00000006; /* source from secondary pixel PLL */ if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
/* no vidrst */ tmp |= 0xC0001000; /* Enable H/V vidrst */
} else {
tmp |= 0x00000002; /* source from VDOCLK */
tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
/* MGA TVO is our clock source */
} }
} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) { } else {
tmp |= 0x00000004; /* source from pixclock */ tmp |= 0x00000002; /* source from VDOCLK */
/* PIXPLL is our clock source */ tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
/* MGA TVO is our clock source */
} }
} else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) tmp |= 0x00000004; /* source from pixclock */
tmp |= 0x00100000; /* connect CRTC2 to DAC */ /* PIXPLL is our clock source */
}
if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
tmp |= 0x00100000; /* connect CRTC2 to DAC */
} }
if (mt->interlaced) { if (mt->interlaced) {
tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */ tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */
...@@ -145,35 +143,63 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, ...@@ -145,35 +143,63 @@ 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 */ if ((mt->HTotal & 7) == 2) {
datactl |= 0x00000010;
mt->HTotal &= ~7;
}
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));
mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1)); mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
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 = m2info->fbcon.var.xres_virtual * (m2info->fbcon.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 */
linelen <<= 1; linelen <<= 1;
m2info->interlaced = 1;
} else { } else {
mga_outl(0x3C28, pos); /* vmemory start */ mga_outl(0x3C28, pos); /* vmemory start */
m2info->interlaced = 0;
} }
mga_outl(0x3C40, linelen); mga_outl(0x3C40, linelen);
} }
mga_outl(0x3C4C, datactl); /* 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_cfbX_init(struct matroxfb_dh_fb_info* m2info, static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
struct display* p) { 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) {
/* no acceleration for secondary head... */ /* no acceleration for secondary head... */
} }
...@@ -182,23 +208,23 @@ static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, ...@@ -182,23 +208,23 @@ static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info,
unsigned int pos; unsigned int pos;
unsigned int linelen; unsigned int linelen;
unsigned int pixelsize; unsigned int pixelsize;
MINFO_FROM(m2info->primary_dev);
#define minfo (m2info->primary_dev) m2info->fbcon.var.xoffset = var->xoffset;
pixelsize = var->bits_per_pixel >> 3; m2info->fbcon.var.yoffset = var->yoffset;
linelen = var->xres_virtual * pixelsize; pixelsize = m2info->fbcon.var.bits_per_pixel >> 3;
pos = var->yoffset * linelen + var->xoffset * pixelsize; linelen = m2info->fbcon.var.xres_virtual * pixelsize;
pos = m2info->fbcon.var.yoffset * linelen + m2info->fbcon.var.xoffset * pixelsize;
pos += m2info->video.offbase; pos += m2info->video.offbase;
if (var->vmode & FB_VMODE_INTERLACED) { if (m2info->interlaced) {
mga_outl(0x3C2C, pos); mga_outl(0x3C2C, pos);
mga_outl(0x3C28, pos + linelen); mga_outl(0x3C28, pos + linelen);
} else { } else {
mga_outl(0x3C28, pos); mga_outl(0x3C28, pos);
} }
#undef minfo
} }
static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info, static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
struct display* p,
struct fb_var_screeninfo* var, struct fb_var_screeninfo* var,
int *visual, int *visual,
int *video_cmap_len, int *video_cmap_len,
...@@ -277,7 +303,7 @@ static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info, ...@@ -277,7 +303,7 @@ static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
} }
static void initMatroxDH(struct matroxfb_dh_fb_info* m2info, struct display* p) { static void initMatroxDH(struct matroxfb_dh_fb_info* m2info, struct display* p) {
switch (p->var.bits_per_pixel) { switch (m2info->fbcon.var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB16 #ifdef FBCON_HAS_CFB16
case 16: case 16:
p->dispsw_data = m2info->cmap.cfb16; p->dispsw_data = m2info->cmap.cfb16;
...@@ -298,7 +324,7 @@ static void initMatroxDH(struct matroxfb_dh_fb_info* m2info, struct display* p) ...@@ -298,7 +324,7 @@ static void initMatroxDH(struct matroxfb_dh_fb_info* m2info, struct display* p)
} }
static int matroxfb_dh_open(struct fb_info* info, int user) { static int matroxfb_dh_open(struct fb_info* info, int user) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
MINFO_FROM(m2info->primary_dev); MINFO_FROM(m2info->primary_dev);
if (MINFO) { if (MINFO) {
...@@ -311,7 +337,7 @@ static int matroxfb_dh_open(struct fb_info* info, int user) { ...@@ -311,7 +337,7 @@ static int matroxfb_dh_open(struct fb_info* info, int user) {
} }
static int matroxfb_dh_release(struct fb_info* info, int user) { static int matroxfb_dh_release(struct fb_info* info, int user) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
MINFO_FROM(m2info->primary_dev); MINFO_FROM(m2info->primary_dev);
if (MINFO) { if (MINFO) {
...@@ -320,49 +346,24 @@ static int matroxfb_dh_release(struct fb_info* info, int user) { ...@@ -320,49 +346,24 @@ static int matroxfb_dh_release(struct fb_info* info, int user) {
#undef m2info #undef m2info
} }
static int matroxfb_dh_get_fix(struct fb_fix_screeninfo* fix, int con, static void matroxfb_dh_update_fix(struct matroxfb_dh_fb_info *m2info) {
struct fb_info* info) { struct fb_fix_screeninfo *fix = &m2info->fbcon.fix;
#define m2info ((struct matroxfb_dh_fb_info*)info)
struct display* p;
if (con >= 0)
p = fb_display + con;
else
p = m2info->fbcon.disp;
memset(fix, 0, sizeof(*fix));
strcpy(fix->id, "MATROX DH"); strcpy(fix->id, "MATROX DH");
fix->smem_start = m2info->video.base; fix->smem_start = m2info->video.base;
fix->smem_len = m2info->video.len_usable; fix->smem_len = m2info->video.len_usable;
fix->type = p->type;
fix->type_aux = p->type_aux;
fix->visual = p->visual;
fix->xpanstep = 8; /* TBD */
fix->ypanstep = 1; fix->ypanstep = 1;
fix->ywrapstep = 0; fix->ywrapstep = 0;
fix->line_length = p->line_length; fix->xpanstep = 8; /* TBD */
fix->mmio_start = m2info->mmio.base; fix->mmio_start = m2info->mmio.base;
fix->mmio_len = m2info->mmio.len; fix->mmio_len = m2info->mmio.len;
fix->accel = 0; /* no accel... */ fix->accel = 0; /* no accel... */
return 0;
#undef m2info
}
static int matroxfb_dh_get_var(struct fb_var_screeninfo* var, int con,
struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info)
if (con < 0)
*var = m2info->fbcon.disp->var;
else
*var = fb_display[con].var;
return 0;
#undef m2info
} }
static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
struct fb_info* info) { struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
struct display* p; struct display* p;
int chgvar; int chgvar;
int visual; int visual;
...@@ -375,7 +376,7 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, ...@@ -375,7 +376,7 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
p = m2info->fbcon.disp; p = m2info->fbcon.disp;
else else
p = fb_display + con; p = fb_display + con;
if ((err = matroxfb_dh_decode_var(m2info, p, var, &visual, &cmap_len, &mode)) != 0) if ((err = matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode)) != 0)
return err; return err;
switch (var->activate & FB_ACTIVATE_MASK) { switch (var->activate & FB_ACTIVATE_MASK) {
case FB_ACTIVATE_TEST: return 0; case FB_ACTIVATE_TEST: return 0;
...@@ -396,13 +397,15 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, ...@@ -396,13 +397,15 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
chgvar = 0; chgvar = 0;
p->var = *var; p->var = *var;
/* cmap */ /* cmap */
m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase); if (con == m2info->fbcon.currcon) {
p->visual = visual; m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
p->ypanstep = 1; m2info->fbcon.var = *var;
p->ywrapstep = 0; m2info->fbcon.fix.visual = visual;
p->type = FB_TYPE_PACKED_PIXELS; m2info->fbcon.fix.type = FB_TYPE_PACKED_PIXELS;
p->type_aux = 0; m2info->fbcon.fix.type_aux = 0;
p->next_line = p->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; p->next_line = m2info->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
matroxfb_dh_update_fix(m2info);
}
p->can_soft_blank = 0; p->can_soft_blank = 0;
p->inverse = 0; /* TBD */ p->inverse = 0; /* TBD */
initMatroxDH(m2info, p); initMatroxDH(m2info, p);
...@@ -411,47 +414,51 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, ...@@ -411,47 +414,51 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
if (con == m2info->fbcon.currcon) { if (con == m2info->fbcon.currcon) {
struct my_timming mt; struct my_timming mt;
unsigned int pos; unsigned int pos;
int out;
int cnt;
matroxfb_var2my(var, &mt); matroxfb_var2my(&m2info->fbcon.var, &mt);
mt.crtc = MATROXFB_SRC_CRTC2;
/* CRTC2 delay */ /* CRTC2 delay */
mt.delay = 34; mt.delay = 34;
pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3; pos = (m2info->fbcon.var.yoffset * m2info->fbcon.var.xres_virtual + m2info->fbcon.var.xoffset) * m2info->fbcon.var.bits_per_pixel >> 3;
pos += m2info->video.offbase; pos += m2info->video.offbase;
DAC1064_global_init(PMINFO2); cnt = 0;
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) { down_read(&ACCESS_FBINFO(altout).lock);
if (ACCESS_FBINFO(primout)) for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
ACCESS_FBINFO(primout)->compute(MINFO, &mt); if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
cnt++;
if (ACCESS_FBINFO(outputs[out]).output->compute) {
ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
}
}
} }
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { ACCESS_FBINFO(crtc2).pixclock = mt.pixclock;
down_read(&ACCESS_FBINFO(altout.lock)); ACCESS_FBINFO(crtc2).mnp = mt.mnp;
if (ACCESS_FBINFO(altout.output)) up_read(&ACCESS_FBINFO(altout).lock);
ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt); if (cnt) {
up_read(&ACCESS_FBINFO(altout.lock)); matroxfb_dh_restore(m2info, &mt, mode, pos);
} else {
matroxfb_dh_disable(m2info);
} }
matroxfb_dh_restore(m2info, &mt, p, mode, pos); DAC1064_global_init(PMINFO2);
DAC1064_global_restore(PMINFO2); DAC1064_global_restore(PMINFO2);
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) { down_read(&ACCESS_FBINFO(altout).lock);
if (ACCESS_FBINFO(primout)) for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
ACCESS_FBINFO(primout)->program(MINFO); if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
} ACCESS_FBINFO(outputs[out]).output->program) {
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
down_read(&ACCESS_FBINFO(altout.lock)); }
if (ACCESS_FBINFO(altout.output))
ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device));
up_read(&ACCESS_FBINFO(altout.lock));
}
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
if (ACCESS_FBINFO(primout))
ACCESS_FBINFO(primout)->start(MINFO);
} }
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
down_read(&ACCESS_FBINFO(altout.lock)); if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
if (ACCESS_FBINFO(altout.output)) ACCESS_FBINFO(outputs[out]).output->start) {
ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device)); ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
up_read(&ACCESS_FBINFO(altout.lock)); }
} }
matroxfb_dh_cfbX_init(m2info, p); up_read(&ACCESS_FBINFO(altout).lock);
matroxfb_dh_cfbX_init(m2info);
my_install_cmap(m2info); my_install_cmap(m2info);
} }
return 0; return 0;
...@@ -460,7 +467,7 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, ...@@ -460,7 +467,7 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con, static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con,
struct fb_info* info) { struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
struct display* dsp; struct display* dsp;
if (con < 0) if (con < 0)
...@@ -479,7 +486,7 @@ static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con, ...@@ -479,7 +486,7 @@ static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con,
static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con, static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con,
struct fb_info* info) { struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
struct display* dsp; struct display* dsp;
if (con < 0) if (con < 0)
...@@ -503,7 +510,7 @@ static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con, ...@@ -503,7 +510,7 @@ static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con,
static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con, static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con,
struct fb_info* info) { struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual || if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual) var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
return -EINVAL; return -EINVAL;
...@@ -525,7 +532,7 @@ static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, stru ...@@ -525,7 +532,7 @@ static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, stru
/* mask out reserved bits + field number (odd/even) */ /* mask out reserved bits + field number (odd/even) */
vblank->vcount = mga_inl(0x3C48) & 0x000007FF; vblank->vcount = mga_inl(0x3C48) & 0x000007FF;
/* compatibility stuff */ /* compatibility stuff */
if (vblank->vcount >= m2info->currcon_display->var.yres) if (vblank->vcount >= m2info->fbcon.var.yres)
vblank->flags |= FB_VBLANK_VBLANKING; vblank->flags |= FB_VBLANK_VBLANKING;
return 0; return 0;
} }
...@@ -536,7 +543,7 @@ static int matroxfb_dh_ioctl(struct inode* inode, ...@@ -536,7 +543,7 @@ static int matroxfb_dh_ioctl(struct inode* inode,
unsigned long arg, unsigned long arg,
int con, int con,
struct fb_info* info) { struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
MINFO_FROM(m2info->primary_dev); MINFO_FROM(m2info->primary_dev);
DBG("matroxfb_crtc2_ioctl") DBG("matroxfb_crtc2_ioctl")
...@@ -563,49 +570,95 @@ static int matroxfb_dh_ioctl(struct inode* inode, ...@@ -563,49 +570,95 @@ static int matroxfb_dh_ioctl(struct inode* inode,
case MATROXFB_SET_OUTPUT_CONNECTION: case MATROXFB_SET_OUTPUT_CONNECTION:
{ {
u_int32_t tmp; u_int32_t tmp;
int out;
int changes;
if (get_user(tmp, (u_int32_t*)arg)) if (get_user(tmp, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
if (tmp & ~ACCESS_FBINFO(output.all)) for (out = 0; out < 32; out++) {
return -EINVAL; if (tmp & (1 << out)) {
if (tmp & ACCESS_FBINFO(output.ph)) if (out >= MATROXFB_MAX_OUTPUTS)
return -EINVAL; return -ENXIO;
if (tmp & MATROXFB_OUTPUT_CONN_DFP) if (!ACCESS_FBINFO(outputs[out]).output)
return -EINVAL; return -ENXIO;
if ((ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) && tmp) switch (ACCESS_FBINFO(outputs[out]).src) {
return -EINVAL; case MATROXFB_SRC_NONE:
if (tmp == ACCESS_FBINFO(output.sh)) case MATROXFB_SRC_CRTC2:
break;
default:
return -EBUSY;
}
}
}
if (ACCESS_FBINFO(devflags.panellink)) {
if (tmp & MATROXFB_OUTPUT_CONN_DFP)
return -EINVAL;
if ((ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) && tmp)
return -EBUSY;
}
changes = 0;
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (tmp & (1 << out)) {
if (ACCESS_FBINFO(outputs[out]).src != MATROXFB_SRC_CRTC2) {
changes = 1;
ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_CRTC2;
}
} else if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
changes = 1;
ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_NONE;
}
}
if (!changes)
return 0; return 0;
ACCESS_FBINFO(output.sh) = tmp;
matroxfb_dh_switch(m2info->fbcon.currcon, info); matroxfb_dh_switch(m2info->fbcon.currcon, info);
return 0; return 0;
} }
case MATROXFB_GET_OUTPUT_CONNECTION: case MATROXFB_GET_OUTPUT_CONNECTION:
{ {
if (put_user(ACCESS_FBINFO(output.sh), (u_int32_t*)arg)) u_int32_t conn = 0;
int out;
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
conn |= 1 << out;
}
}
if (put_user(conn, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case MATROXFB_GET_AVAILABLE_OUTPUTS: case MATROXFB_GET_AVAILABLE_OUTPUTS:
{ {
u_int32_t tmp; u_int32_t tmp = 0;
int out;
/* we do not support DFP from CRTC2 */
tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph) & ~MATROXFB_OUTPUT_CONN_DFP; for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
/* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */ if (ACCESS_FBINFO(outputs[out]).output) {
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) switch (ACCESS_FBINFO(outputs[out]).src) {
tmp = 0; case MATROXFB_SRC_NONE:
case MATROXFB_SRC_CRTC2:
tmp |= 1 << out;
break;
}
}
}
if (ACCESS_FBINFO(devflags.panellink)) {
tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) {
tmp = 0;
}
}
if (put_user(tmp, (u_int32_t*)arg)) if (put_user(tmp, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
} }
return -EINVAL; return -ENOTTY;
#undef m2info #undef m2info
} }
static int matroxfb_dh_blank(int blank, struct fb_info* info) { static int matroxfb_dh_blank(int blank, struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
switch (blank) { switch (blank) {
case 1: case 1:
case 2: case 2:
...@@ -622,8 +675,6 @@ static struct fb_ops matroxfb_dh_ops = { ...@@ -622,8 +675,6 @@ static struct fb_ops matroxfb_dh_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_open = matroxfb_dh_open, .fb_open = matroxfb_dh_open,
.fb_release = matroxfb_dh_release, .fb_release = matroxfb_dh_release,
.fb_get_fix = matroxfb_dh_get_fix,
.fb_get_var = matroxfb_dh_get_var,
.fb_set_var = matroxfb_dh_set_var, .fb_set_var = matroxfb_dh_set_var,
.fb_get_cmap = matroxfb_dh_get_cmap, .fb_get_cmap = matroxfb_dh_get_cmap,
.fb_set_cmap = matroxfb_dh_set_cmap, .fb_set_cmap = matroxfb_dh_set_cmap,
...@@ -634,7 +685,7 @@ static struct fb_ops matroxfb_dh_ops = { ...@@ -634,7 +685,7 @@ static struct fb_ops matroxfb_dh_ops = {
}; };
static int matroxfb_dh_switch(int con, struct fb_info* info) { static int matroxfb_dh_switch(int con, struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
struct fb_cmap* cmap; struct fb_cmap* cmap;
struct display* p; struct display* p;
...@@ -657,7 +708,7 @@ static int matroxfb_dh_switch(int con, struct fb_info* info) { ...@@ -657,7 +708,7 @@ static int matroxfb_dh_switch(int con, struct fb_info* info) {
} }
static int matroxfb_dh_updatevar(int con, struct fb_info* info) { static int matroxfb_dh_updatevar(int con, struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info) #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
matroxfb_dh_pan_var(m2info, &fb_display[con].var); matroxfb_dh_pan_var(m2info, &fb_display[con].var);
return 0; return 0;
#undef m2info #undef m2info
...@@ -730,11 +781,10 @@ static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) { ...@@ -730,11 +781,10 @@ static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) {
/* /*
* If we have unused output, connect CRTC2 to it... * If we have unused output, connect CRTC2 to it...
*/ */
if ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) && if (ACCESS_FBINFO(outputs[1]).output &&
!(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) && ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_NONE &&
!(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) { ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_NONE) {
ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY; ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC2;
ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP;
} }
matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon); matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon);
...@@ -747,7 +797,7 @@ static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) { ...@@ -747,7 +797,7 @@ static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) {
} }
down_write(&ACCESS_FBINFO(crtc2.lock)); down_write(&ACCESS_FBINFO(crtc2.lock));
oldcrtc2 = ACCESS_FBINFO(crtc2.info); oldcrtc2 = ACCESS_FBINFO(crtc2.info);
ACCESS_FBINFO(crtc2.info) = &m2info->fbcon; ACCESS_FBINFO(crtc2.info) = m2info;
up_write(&ACCESS_FBINFO(crtc2.lock)); up_write(&ACCESS_FBINFO(crtc2.lock));
if (oldcrtc2) { if (oldcrtc2) {
printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n", printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n",
...@@ -776,16 +826,16 @@ static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info* m2info) { ...@@ -776,16 +826,16 @@ static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info* m2info) {
#define minfo (m2info->primary_dev) #define minfo (m2info->primary_dev)
if (m2info->fbcon_registered) { if (m2info->fbcon_registered) {
int id; int id;
struct fb_info* crtc2; struct matroxfb_dh_fb_info* crtc2;
down_write(&ACCESS_FBINFO(crtc2.lock)); down_write(&ACCESS_FBINFO(crtc2.lock));
crtc2 = ACCESS_FBINFO(crtc2.info); crtc2 = ACCESS_FBINFO(crtc2.info);
if (crtc2 == &m2info->fbcon) if (crtc2 == m2info)
ACCESS_FBINFO(crtc2.info) = NULL; ACCESS_FBINFO(crtc2.info) = NULL;
up_write(&ACCESS_FBINFO(crtc2.lock)); up_write(&ACCESS_FBINFO(crtc2.lock));
if (crtc2 != &m2info->fbcon) { if (crtc2 != m2info) {
printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n", printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n",
crtc2, &m2info->fbcon); crtc2, m2info);
printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n"); printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n");
return; return;
} }
...@@ -823,6 +873,7 @@ static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) { ...@@ -823,6 +873,7 @@ static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) {
static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) { static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) {
matroxfb_dh_deregisterfb(crtc2); matroxfb_dh_deregisterfb(crtc2);
kfree(crtc2);
} }
static struct matroxfb_driver crtc2 = { static struct matroxfb_driver crtc2 = {
...@@ -839,7 +890,7 @@ static void matroxfb_crtc2_exit(void) { ...@@ -839,7 +890,7 @@ static void matroxfb_crtc2_exit(void) {
matroxfb_unregister_driver(&crtc2); matroxfb_unregister_driver(&crtc2);
} }
MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Matrox G400 CRTC2 driver"); MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(matroxfb_crtc2_init); module_init(matroxfb_crtc2_init);
......
...@@ -27,8 +27,9 @@ struct matroxfb_dh_fb_info { ...@@ -27,8 +27,9 @@ struct matroxfb_dh_fb_info {
unsigned int len; unsigned int len;
} mmio; } mmio;
int currcon;
struct display* currcon_display; struct display* currcon_display;
int interlaced:1;
union { union {
#ifdef FBCON_HAS_CFB16 #ifdef FBCON_HAS_CFB16
......
...@@ -2,145 +2,418 @@ ...@@ -2,145 +2,418 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
* *
* (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-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/02
* *
* See matroxfb_base.c for contributors. * See matroxfb_base.c for contributors.
* *
*/ */
#include "matroxfb_g450.h" #include "matroxfb_base.h"
#include "matroxfb_misc.h" #include "matroxfb_misc.h"
#include "matroxfb_DAC1064.h" #include "matroxfb_DAC1064.h"
#include "g450_pll.h" #include "g450_pll.h"
#include <linux/matroxfb.h> #include <linux/matroxfb.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/div64.h>
static int matroxfb_g450_compute(void* md, struct my_timming* mt) { static void cve2_set_reg(WPMINFO int reg, int val) {
#define m2info ((struct matroxfb_g450_info*)md) unsigned long flags;
#define minfo (m2info->primary_dev)
ACCESS_FBINFO(hw).vidclk = mt->pixclock;
#undef minfo
#undef m2info
return 0;
}
static int matroxfb_g450_program(void* md) { matroxfb_DAC_lock_irqsave(flags);
#define m2info ((struct matroxfb_g450_info*)md) matroxfb_DAC_out(PMINFO 0x87, reg);
#define minfo (m2info->primary_dev) matroxfb_DAC_out(PMINFO 0x88, val);
matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(hw).vidclk, M_VIDEO_PLL); matroxfb_DAC_unlock_irqrestore(flags);
#undef minfo
#undef m2info
return 0;
} }
static int matroxfb_g450_start(void* md) { struct output_desc {
return 0; unsigned int h_vis;
} unsigned int h_f_porch;
unsigned int h_sync;
unsigned int h_b_porch;
unsigned long long int chromasc;
unsigned int burst;
unsigned int v_total;
};
static void matroxfb_g450_incuse(void* md) { static void computeRegs(WPMINFO struct mavenregs* r, struct my_timming* mt, const struct output_desc* outd) {
MOD_INC_USE_COUNT; u_int32_t chromasc;
} u_int32_t hlen;
u_int32_t hsl;
u_int32_t hbp;
u_int32_t hfp;
u_int32_t hvis;
unsigned int pixclock;
unsigned long long piic;
int mnp;
int over;
r->regs[0x80] = 0x03; /* | 0x40 for SCART */
hvis = ((mt->HDisplay << 1) + 3) & ~3;
if (hvis >= 2048) {
hvis = 2044;
}
piic = 1000000000ULL * hvis;
do_div(piic, outd->h_vis);
dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic);
mnp = matroxfb_g450_setclk(PMINFO piic, M_VIDEO_PLL);
mt->mnp = mnp;
mt->pixclock = g450_mnp2f(PMINFO mnp);
static void matroxfb_g450_decuse(void* md) { dprintk(KERN_DEBUG "MNP=%08X\n", mnp);
MOD_DEC_USE_COUNT;
pixclock = 1000000000U / mt->pixclock;
dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock);
piic = outd->chromasc;
do_div(piic, mt->pixclock);
chromasc = piic;
dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc);
r->regs[0] = piic >> 24;
r->regs[1] = piic >> 16;
r->regs[2] = piic >> 8;
r->regs[3] = piic >> 0;
hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1;
hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1;
hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1;
hlen = hvis + hfp + hsl + hbp;
over = hlen & 0x0F;
dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen);
if (over) {
hfp -= over;
hlen -= over;
if (over <= 2) {
} else if (over < 10) {
hfp += 4;
hlen += 4;
} else {
hfp += 16;
hlen += 16;
}
}
/* maybe cve2 has requirement 800 < hlen < 1184 */
r->regs[0x08] = hsl;
r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock; /* burst length */
r->regs[0x0A] = hbp;
r->regs[0x2C] = hfp;
r->regs[0x31] = hvis / 8;
r->regs[0x32] = hvis & 7;
dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen);
r->regs[0x84] = 1; /* x sync point */
r->regs[0x85] = 0;
hvis = hvis >> 1;
hlen = hlen >> 1;
dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis);
mt->interlaced = 1;
mt->HDisplay = hvis & ~7;
mt->HSyncStart = mt->HDisplay + 8;
mt->HSyncEnd = (hlen & ~7) - 8;
mt->HTotal = hlen;
{
int upper;
unsigned int vtotal;
unsigned int vsyncend;
unsigned int vdisplay;
vtotal = mt->VTotal;
vsyncend = mt->VSyncEnd;
vdisplay = mt->VDisplay;
if (vtotal < outd->v_total) {
unsigned int yovr = outd->v_total - vtotal;
vsyncend += yovr >> 1;
} else if (vtotal > outd->v_total) {
vdisplay = outd->v_total - 4;
vsyncend = outd->v_total;
}
upper = (outd->v_total - vsyncend) >> 1; /* in field lines */
r->regs[0x17] = outd->v_total / 4;
r->regs[0x18] = outd->v_total & 3;
r->regs[0x33] = upper - 1; /* upper blanking */
r->regs[0x82] = upper; /* y sync point */
r->regs[0x83] = upper >> 8;
mt->VDisplay = vdisplay;
mt->VSyncStart = outd->v_total - 2;
mt->VSyncEnd = outd->v_total;
mt->VTotal = outd->v_total;
}
} }
static int matroxfb_g450_set_mode(void* md, u_int32_t arg) { static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
if (arg == MATROXFB_OUTPUT_MODE_MONITOR) { static const struct output_desc paloutd = {
return 1; .h_vis = 52148148, // ps
.h_f_porch = 1407407, // ps
.h_sync = 4666667, // ps
.h_b_porch = 5777778, // ps
.chromasc = 19042247534182ULL, // 4433618.750 Hz
.burst = 2518518, // ps
.v_total = 625,
};
static const struct output_desc ntscoutd = {
.h_vis = 52888889, // ps
.h_f_porch = 1333333, // ps
.h_sync = 4666667, // ps
.h_b_porch = 4666667, // ps
.chromasc = 15374030659475ULL, // 3579545.454 Hz
.burst = 2418418, // ps
.v_total = 525, // lines
};
static const struct mavenregs palregs = { {
0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
0x00,
0x00, /* test */
0xF9, /* modified by code (F9 written...) */
0x00, /* ? not written */
0x7E, /* 08 */
0x44, /* 09 */
0x9C, /* 0A */
0x2E, /* 0B */
0x21, /* 0C */
0x00, /* ? not written */
// 0x3F, 0x03, /* 0E-0F */
0x3C, 0x03,
0x3C, 0x03, /* 10-11 */
0x1A, /* 12 */
0x2A, /* 13 */
0x1C, 0x3D, 0x14, /* 14-16 */
0x9C, 0x01, /* 17-18 */
0x00, /* 19 */
0xFE, /* 1A */
0x7E, /* 1B */
0x60, /* 1C */
0x05, /* 1D */
// 0x89, 0x03, /* 1E-1F */
0xAD, 0x03,
// 0x72, /* 20 */
0xA5,
0x07, /* 21 */
// 0x72, /* 22 */
0xA5,
0x00, /* 23 */
0x00, /* 24 */
0x00, /* 25 */
0x08, /* 26 */
0x04, /* 27 */
0x00, /* 28 */
0x1A, /* 29 */
0x55, 0x01, /* 2A-2B */
0x26, /* 2C */
0x07, 0x7E, /* 2D-2E */
0x02, 0x54, /* 2F-30 */
0xB0, 0x00, /* 31-32 */
0x14, /* 33 */
0x49, /* 34 */
0x00, /* 35 written multiple times */
0x00, /* 36 not written */
0xA3, /* 37 */
0xC8, /* 38 */
0x22, /* 39 */
0x02, /* 3A */
0x22, /* 3B */
0x3F, 0x03, /* 3C-3D */
0x00, /* 3E written multiple times */
0x00, /* 3F not written */
} };
static struct mavenregs ntscregs = { {
0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
0x00,
0x00, /* test */
0xF9, /* modified by code (F9 written...) */
0x00, /* ? not written */
0x7E, /* 08 */
0x43, /* 09 */
0x7E, /* 0A */
0x3D, /* 0B */
0x00, /* 0C */
0x00, /* ? not written */
0x41, 0x00, /* 0E-0F */
0x3C, 0x00, /* 10-11 */
0x17, /* 12 */
0x21, /* 13 */
0x1B, 0x1B, 0x24, /* 14-16 */
0x83, 0x01, /* 17-18 */
0x00, /* 19 */
0x0F, /* 1A */
0x0F, /* 1B */
0x60, /* 1C */
0x05, /* 1D */
//0x89, 0x02, /* 1E-1F */
0xC0, 0x02, /* 1E-1F */
//0x5F, /* 20 */
0x9C, /* 20 */
0x04, /* 21 */
//0x5F, /* 22 */
0x9C, /* 22 */
0x01, /* 23 */
0x02, /* 24 */
0x00, /* 25 */
0x0A, /* 26 */
0x05, /* 27 */
0x00, /* 28 */
0x10, /* 29 */
0xFF, 0x03, /* 2A-2B */
0x24, /* 2C */
0x0F, 0x78, /* 2D-2E */
0x00, 0x00, /* 2F-30 */
0xB2, 0x04, /* 31-32 */
0x14, /* 33 */
0x02, /* 34 */
0x00, /* 35 written multiple times */
0x00, /* 36 not written */
0xA3, /* 37 */
0xC8, /* 38 */
0x15, /* 39 */
0x05, /* 3A */
0x3B, /* 3B */
0x3C, 0x00, /* 3C-3D */
0x00, /* 3E written multiple times */
0x00, /* never written */
} };
if (norm == MATROXFB_OUTPUT_MODE_PAL) {
*data = palregs;
*outd = &paloutd;
} else {
*data = ntscregs;
*outd = &ntscoutd;
} }
return -EINVAL; return;
} }
static int matroxfb_g450_get_mode(void* md, u_int32_t* arg) { #define LR(x) cve2_set_reg(PMINFO (x), m->regs[(x)])
*arg = MATROXFB_OUTPUT_MODE_MONITOR; static void cve2_init_TV(WPMINFO const struct mavenregs* m) {
return 0; int i;
LR(0x80);
LR(0x82); LR(0x83);
LR(0x84); LR(0x85);
cve2_set_reg(PMINFO 0x3E, 0x01);
for (i = 0; i < 0x3E; i++) {
LR(i);
}
cve2_set_reg(PMINFO 0x3E, 0x00);
} }
static struct matrox_altout matroxfb_g450_altout = { static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
matroxfb_g450_compute, MINFO_FROM(md);
matroxfb_g450_program,
matroxfb_g450_start, dprintk(KERN_DEBUG "Computing, mode=%u\n", ACCESS_FBINFO(outputs[1]).mode);
matroxfb_g450_incuse,
matroxfb_g450_decuse,
matroxfb_g450_set_mode,
matroxfb_g450_get_mode
};
static int matroxfb_g450_connect(struct matroxfb_g450_info* m2info) { if (mt->crtc == MATROXFB_SRC_CRTC2 &&
MINFO_FROM(m2info->primary_dev); ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
const struct output_desc* outd;
down_write(&ACCESS_FBINFO(altout.lock)); cve2_init_TVdata(ACCESS_FBINFO(outputs[1]).mode, &ACCESS_FBINFO(hw).maven, &outd);
ACCESS_FBINFO(altout.device) = m2info; computeRegs(PMINFO &ACCESS_FBINFO(hw).maven, mt, outd);
ACCESS_FBINFO(altout.output) = &matroxfb_g450_altout; } else if (mt->mnp < 0) {
up_write(&ACCESS_FBINFO(altout.lock)); /* We must program clocks before CRTC2, otherwise interlaced mode
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY; startup may fail */
matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), (struct fb_info*)MINFO); 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);
}
dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
return 0; return 0;
} }
static void matroxfb_g450_shutdown(struct matroxfb_g450_info* m2info) { static int matroxfb_g450_program(void* md) {
MINFO_FROM(m2info->primary_dev); MINFO_FROM(md);
if (MINFO) { if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
ACCESS_FBINFO(output.all) &= ~MATROXFB_OUTPUT_CONN_SECONDARY; cve2_init_TV(PMINFO &ACCESS_FBINFO(hw).maven);
ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
down_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(altout.device) = NULL;
ACCESS_FBINFO(altout.output) = NULL;
up_write(&ACCESS_FBINFO(altout.lock));
m2info->primary_dev = NULL;
} }
return 0;
} }
/* we do not have __setup() yet */ static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
static void* matroxfb_g450_probe(struct matrox_fb_info* minfo) { switch (arg) {
struct matroxfb_g450_info* m2info; case MATROXFB_OUTPUT_MODE_PAL:
case MATROXFB_OUTPUT_MODE_NTSC:
/* hardware is not G450... */ case MATROXFB_OUTPUT_MODE_MONITOR:
if (!ACCESS_FBINFO(devflags.g450dac)) return 0;
return NULL;
m2info = (struct matroxfb_g450_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
if (!m2info) {
printk(KERN_ERR "matroxfb_g450: Not enough memory for G450 DAC control structs\n");
return NULL;
}
memset(m2info, 0, sizeof(*m2info));
m2info->primary_dev = MINFO;
if (matroxfb_g450_connect(m2info)) {
kfree(m2info);
printk(KERN_ERR "matroxfb_g450: G450 DAC failed to initialize\n");
return NULL;
} }
return m2info; return -EINVAL;
} }
static void matroxfb_g450_remove(struct matrox_fb_info* minfo, void* g450) { static int g450_dvi_compute(void* md, struct my_timming* mt) {
matroxfb_g450_shutdown(g450); MINFO_FROM(md);
kfree(g450);
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;
} }
static struct matroxfb_driver g450 = { static struct matrox_altout matroxfb_g450_altout = {
.name = "Matrox G450 output #2", .name = "Secondary output",
.probe = matroxfb_g450_probe, .compute = matroxfb_g450_compute,
.remove = matroxfb_g450_remove }; .program = matroxfb_g450_program,
.verifymode = matroxfb_g450_verify_mode,
};
static int matroxfb_g450_init(void) { static struct matrox_altout matroxfb_g450_dvi = {
matroxfb_register_driver(&g450); .name = "DVI output",
return 0; .compute = g450_dvi_compute,
};
void matroxfb_g450_connect(WPMINFO2) {
if (ACCESS_FBINFO(devflags.g450dac)) {
down_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC1;
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));
}
} }
static void matroxfb_g450_exit(void) { void matroxfb_g450_shutdown(WPMINFO2) {
matroxfb_unregister_driver(&g450); if (ACCESS_FBINFO(devflags.g450dac)) {
down_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
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));
}
} }
MODULE_AUTHOR("(c) 2000-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); EXPORT_SYMBOL(matroxfb_g450_connect);
MODULE_DESCRIPTION("Matrox G450 secondary output driver"); EXPORT_SYMBOL(matroxfb_g450_shutdown);
MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Matrox G450/G550 output driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(matroxfb_g450_init);
module_exit(matroxfb_g450_exit);
#ifndef __MATROXFB_G450_H__ #ifndef __MATROXFB_G450_H__
#define __MATROXFB_G450_H__ #define __MATROXFB_G450_H__
#include <linux/ioctl.h>
#include "matroxfb_base.h" #include "matroxfb_base.h"
struct matroxfb_g450_info { #ifdef CONFIG_FB_MATROX_G450
struct matrox_fb_info* primary_dev; void matroxfb_g450_connect(WPMINFO2);
unsigned int timmings; void matroxfb_g450_shutdown(WPMINFO2);
}; #else
static inline void matroxfb_g450_connect(WPMINFO2) { };
static inline void matroxfb_g450_shutdown(WPMINFO2) { };
#endif
#endif /* __MATROXFB_MAVEN_H__ */ #endif /* __MATROXFB_G450_H__ */
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
* *
* (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-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
* *
* See matroxfb_base.c for contributors. * See matroxfb_base.c for contributors.
* *
...@@ -22,18 +22,12 @@ ...@@ -22,18 +22,12 @@
#define MAVEN_I2CID (0x1B) #define MAVEN_I2CID (0x1B)
#define MODE_PAL MATROXFB_OUTPUT_MODE_PAL
#define MODE_NTSC MATROXFB_OUTPUT_MODE_NTSC
#define MODE_TV(x) (((x) == MODE_PAL) || ((x) == MODE_NTSC))
#define MODE_MONITOR MATROXFB_OUTPUT_MODE_MONITOR
#define MGATVO_B 1 #define MGATVO_B 1
#define MGATVO_C 2 #define MGATVO_C 2
struct maven_data { struct maven_data {
struct matrox_fb_info* primary_head; struct matrox_fb_info* primary_head;
struct i2c_client* client; struct i2c_client* client;
int mode;
int version; int version;
}; };
...@@ -127,7 +121,7 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, ...@@ -127,7 +121,7 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
fwant = htotal * vtotal; fwant = htotal * vtotal;
fmax = pll->vco_freq_max / ctl->den; fmax = pll->vco_freq_max / ctl->den;
printk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n", dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
fwant, fxtal, htotal, vtotal, fmax); fwant, fxtal, htotal, vtotal, fmax);
for (p = 1; p <= pll->post_shift_max; p++) { for (p = 1; p <= pll->post_shift_max; p++) {
if (fwant * 2 > fmax) if (fwant * 2 > fmax)
...@@ -163,9 +157,9 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, ...@@ -163,9 +157,9 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
ln = ln - scrlen; ln = ln - scrlen;
if (ln > htotal) if (ln > htotal)
continue; continue;
printk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln); dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
if (ln > besth2) { if (ln > besth2) {
printk(KERN_DEBUG "Better...\n"); dprintk(KERN_DEBUG "Better...\n");
*h2 = besth2 = ln; *h2 = besth2 = ln;
*post = p; *post = p;
*in = m; *in = m;
...@@ -221,6 +215,13 @@ static void DAC1064_calcclock(unsigned int freq, unsigned int fmax, ...@@ -221,6 +215,13 @@ static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
return; return;
} }
static unsigned char maven_compute_deflicker (const struct maven_data* md) {
unsigned char df;
df = (md->version == MGATVO_B?0x40:0x00);
return df;
}
static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) { static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
static struct mavenregs palregs = { { static struct mavenregs palregs = { {
0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */ 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
...@@ -273,7 +274,7 @@ static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* dat ...@@ -273,7 +274,7 @@ static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* dat
0x3F, 0x03, /* 3C-3D */ 0x3F, 0x03, /* 3C-3D */
0x00, /* 3E written multiple times */ 0x00, /* 3E written multiple times */
0x00, /* 3F not written */ 0x00, /* 3F not written */
}, MODE_PAL, 625, 50 }; }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
static struct mavenregs ntscregs = { { static struct mavenregs ntscregs = { {
0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */ 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
0x00, 0x00,
...@@ -325,14 +326,16 @@ static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* dat ...@@ -325,14 +326,16 @@ static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* dat
0x3C, 0x00, /* 3C-3D */ 0x3C, 0x00, /* 3C-3D */
0x00, /* 3E written multiple times */ 0x00, /* 3E written multiple times */
0x00, /* never written */ 0x00, /* never written */
}, MODE_NTSC, 525, 60 }; }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
MINFO_FROM(md->primary_head);
if (md->mode & MODE_PAL) if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_PAL)
*data = palregs; *data = palregs;
else else
*data = ntscregs; *data = ntscregs;
data->regs[0x93] = 0xA2; /* Set deflicker */
data->regs[0x93] = maven_compute_deflicker(md);
/* gamma correction registers */ /* gamma correction registers */
data->regs[0x83] = 0x00; data->regs[0x83] = 0x00;
...@@ -386,7 +389,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) { ...@@ -386,7 +389,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
LRP(0x17); LRP(0x17);
LR(0x0B); LR(0x0B);
LR(0x0C); LR(0x0C);
if (m->mode & MODE_PAL) { if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
maven_set_reg(c, 0x35, 0x10); /* ... */ maven_set_reg(c, 0x35, 0x10); /* ... */
} else { } else {
maven_set_reg(c, 0x35, 0x0F); /* ... */ maven_set_reg(c, 0x35, 0x0F); /* ... */
...@@ -424,7 +427,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) { ...@@ -424,7 +427,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
LR(0x27); LR(0x27);
LR(0x21); LR(0x21);
LRP(0x2A); LRP(0x2A);
if (m->mode & MODE_PAL) if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
maven_set_reg(c, 0x35, 0x1D); /* ... */ maven_set_reg(c, 0x35, 0x1D); /* ... */
else else
maven_set_reg(c, 0x35, 0x1C); maven_set_reg(c, 0x35, 0x1C);
...@@ -473,7 +476,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) { ...@@ -473,7 +476,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
LR(0xC2); LR(0xC2);
maven_get_reg(c, 0x8D); maven_get_reg(c, 0x8D);
maven_set_reg(c, 0x8D, 0x00); maven_set_reg(c, 0x8D, 0x04);
LR(0x20); /* saturation #1 */ LR(0x20); /* saturation #1 */
LR(0x22); /* saturation #2 */ LR(0x22); /* saturation #2 */
...@@ -498,7 +501,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) { ...@@ -498,7 +501,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
LR(0x8B); LR(0x8B);
val = maven_get_reg(c, 0x8D); val = maven_get_reg(c, 0x8D);
val &= 0x10; /* 0x10 or anything ored with it */ val &= 0x14; /* 0x10 or anything ored with it */
maven_set_reg(c, 0x8D, val); maven_set_reg(c, 0x8D, val);
LR(0x33); LR(0x33);
...@@ -524,7 +527,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) { ...@@ -524,7 +527,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
LR(0x27); LR(0x27);
LR(0x21); LR(0x21);
LRP(0x2A); LRP(0x2A);
if (m->mode & MODE_PAL) if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
maven_set_reg(c, 0x35, 0x1D); maven_set_reg(c, 0x35, 0x1D);
else else
maven_set_reg(c, 0x35, 0x1C); maven_set_reg(c, 0x35, 0x1C);
...@@ -562,7 +565,7 @@ static int maven_find_exact_clocks(unsigned int ht, unsigned int vt, ...@@ -562,7 +565,7 @@ static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
unsigned int a, b, c, h2; unsigned int a, b, c, h2;
unsigned int h = ht + 2 + x; unsigned int h = ht + 2 + x;
if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
unsigned int diff = h - h2; unsigned int diff = h - h2;
if (diff < err) { if (diff < err) {
...@@ -583,9 +586,10 @@ static inline int maven_compute_timming(struct maven_data* md, ...@@ -583,9 +586,10 @@ static inline int maven_compute_timming(struct maven_data* md,
struct mavenregs* m) { struct mavenregs* m) {
unsigned int tmpi; unsigned int tmpi;
unsigned int a, bv, c; unsigned int a, bv, c;
MINFO_FROM(md->primary_head);
m->mode = md->mode; m->mode = ACCESS_FBINFO(outputs[1]).mode;
if (MODE_TV(md->mode)) { if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
unsigned int lmargin; unsigned int lmargin;
unsigned int umargin; unsigned int umargin;
unsigned int vslen; unsigned int vslen;
...@@ -804,7 +808,7 @@ static inline int maven_compute_timming(struct maven_data* md, ...@@ -804,7 +808,7 @@ static inline int maven_compute_timming(struct maven_data* md,
m->regs[0xB0] = 0x03; /* output: monitor */ m->regs[0xB0] = 0x03; /* output: monitor */
m->regs[0xB1] = 0xA0; /* ??? */ m->regs[0xB1] = 0xA0; /* ??? */
m->regs[0x8C] = 0x20; /* must be set... */ m->regs[0x8C] = 0x20; /* must be set... */
m->regs[0x8D] = 0x00; /* defaults to 0x10: test signal */ m->regs[0x8D] = 0x04; /* defaults to 0x10: test signal */
m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */ m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
m->regs[0xBF] = 0x22; /* makes picture stable */ m->regs[0xBF] = 0x22; /* makes picture stable */
...@@ -815,7 +819,7 @@ static inline int maven_program_timming(struct maven_data* md, ...@@ -815,7 +819,7 @@ static inline int maven_program_timming(struct maven_data* md,
const struct mavenregs* m) { const struct mavenregs* m) {
struct i2c_client* c = md->client; struct i2c_client* c = md->client;
if (m->mode & MODE_MONITOR) { if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
LR(0x80); LR(0x80);
LR(0x81); LR(0x81);
LR(0x82); LR(0x82);
...@@ -855,22 +859,16 @@ static inline int maven_resync(struct maven_data* md) { ...@@ -855,22 +859,16 @@ static inline int maven_resync(struct maven_data* md) {
return 0; return 0;
} }
static int maven_set_output_mode(struct maven_data* md, u_int32_t arg) { static int maven_verify_output_mode(struct maven_data* md, u_int32_t arg) {
switch (arg) { switch (arg) {
case MATROXFB_OUTPUT_MODE_PAL: case MATROXFB_OUTPUT_MODE_PAL:
case MATROXFB_OUTPUT_MODE_NTSC: case MATROXFB_OUTPUT_MODE_NTSC:
case MATROXFB_OUTPUT_MODE_MONITOR: case MATROXFB_OUTPUT_MODE_MONITOR:
md->mode = arg; return 0;
return 1;
} }
return -EINVAL; return -EINVAL;
} }
static int maven_get_output_mode(struct maven_data* md, u_int32_t *arg) {
*arg = md->mode;
return 0;
}
/******************************************************/ /******************************************************/
static int maven_out_compute(void* md, struct my_timming* mt) { static int maven_out_compute(void* md, struct my_timming* mt) {
...@@ -893,48 +891,31 @@ static int maven_out_start(void* md) { ...@@ -893,48 +891,31 @@ static int maven_out_start(void* md) {
return maven_resync(md); return maven_resync(md);
} }
static void maven_out_incuse(void* md) { static int maven_out_verify_mode(void* md, u_int32_t arg) {
if (md) return maven_verify_output_mode(md, arg);
i2c_inc_use_client(((struct maven_data*)md)->client);
}
static void maven_out_decuse(void* md) {
if (md)
i2c_dec_use_client(((struct maven_data*)md)->client);
}
static int maven_out_set_mode(void* md, u_int32_t arg) {
return maven_set_output_mode(md, arg);
}
static int maven_out_get_mode(void* md, u_int32_t* arg) {
return maven_get_output_mode(md, arg);
} }
static struct matrox_altout maven_altout = { static struct matrox_altout maven_altout = {
maven_out_compute, .name = "Secondary output",
maven_out_program, .compute = maven_out_compute,
maven_out_start, .program = maven_out_program,
maven_out_incuse, .start = maven_out_start,
maven_out_decuse, .verifymode = maven_out_verify_mode,
maven_out_set_mode,
maven_out_get_mode
}; };
static int maven_init_client(struct i2c_client* clnt) { static int maven_init_client(struct i2c_client* clnt) {
struct i2c_adapter* a = clnt->adapter; struct i2c_adapter* a = clnt->adapter;
struct maven_data* md = clnt->data; struct maven_data* md = clnt->data;
struct matroxfb_dh_maven_info* m2info __attribute__((unused)) = ((struct i2c_bit_adapter*)a)->minfo; MINFO_FROM(container_of(a, struct i2c_bit_adapter, adapter)->minfo);
MINFO_FROM(m2info->primary_dev);
md->mode = MODE_MONITOR;
md->primary_head = MINFO; md->primary_head = MINFO;
md->client = clnt; md->client = clnt;
down_write(&ACCESS_FBINFO(altout.lock)); down_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(altout.device) = md; ACCESS_FBINFO(outputs[1]).output = &maven_altout;
ACCESS_FBINFO(altout.output) = &maven_altout; ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
ACCESS_FBINFO(outputs[1]).data = md;
ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
up_write(&ACCESS_FBINFO(altout.lock)); up_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
if (maven_get_reg(clnt, 0xB2) < 0x14) { if (maven_get_reg(clnt, 0xB2) < 0x14) {
md->version = MGATVO_B; md->version = MGATVO_B;
} else { } else {
...@@ -947,13 +928,14 @@ static int maven_shutdown_client(struct i2c_client* clnt) { ...@@ -947,13 +928,14 @@ static int maven_shutdown_client(struct i2c_client* clnt) {
struct maven_data* md = clnt->data; struct maven_data* md = clnt->data;
if (md->primary_head) { if (md->primary_head) {
md->primary_head->output.all &= ~MATROXFB_OUTPUT_CONN_SECONDARY; MINFO_FROM(md->primary_head);
md->primary_head->output.ph &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
md->primary_head->output.sh &= ~MATROXFB_OUTPUT_CONN_SECONDARY; down_write(&ACCESS_FBINFO(altout.lock));
down_write(&md->primary_head->altout.lock); ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
md->primary_head->altout.device = NULL; ACCESS_FBINFO(outputs[1]).output = NULL;
md->primary_head->altout.output = NULL; ACCESS_FBINFO(outputs[1]).data = NULL;
up_write(&md->primary_head->altout.lock); ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
up_write(&ACCESS_FBINFO(altout.lock));
md->primary_head = NULL; md->primary_head = NULL;
} }
return 0; return 0;
...@@ -983,7 +965,7 @@ static int maven_detect_client(struct i2c_adapter* adapter, int address, unsigne ...@@ -983,7 +965,7 @@ static int maven_detect_client(struct i2c_adapter* adapter, int address, unsigne
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_PROTOCOL_MANGLING)) I2C_FUNC_PROTOCOL_MANGLING))
goto ERROR0; goto ERROR0;
if (!(new_client = (struct i2c_client*)kmalloc(sizeof(struct i2c_client) + sizeof(struct maven_data), if (!(new_client = (struct i2c_client*)kmalloc(sizeof(*new_client) + sizeof(*data),
GFP_KERNEL))) { GFP_KERNEL))) {
err = -ENOMEM; err = -ENOMEM;
goto ERROR0; goto ERROR0;
...@@ -1066,7 +1048,7 @@ static void matroxfb_maven_exit(void) { ...@@ -1066,7 +1048,7 @@ static void matroxfb_maven_exit(void) {
i2c_del_driver(&maven_driver); i2c_del_driver(&maven_driver);
} }
MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver"); MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(matroxfb_maven_init); module_init(matroxfb_maven_init);
......
...@@ -6,21 +6,15 @@ ...@@ -6,21 +6,15 @@
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include "matroxfb_base.h" #include "matroxfb_base.h"
struct matroxfb_dh_maven_info;
struct i2c_bit_adapter { struct i2c_bit_adapter {
struct i2c_adapter adapter; struct i2c_adapter adapter;
int initialized; int initialized;
struct i2c_algo_bit_data bac; struct i2c_algo_bit_data bac;
struct matroxfb_dh_maven_info *minfo; struct matrox_fb_info* minfo;
}; struct {
unsigned int data;
struct matroxfb_dh_maven_info { unsigned int clock;
struct matrox_fb_info* primary_dev; } mask;
struct i2c_bit_adapter maven;
struct i2c_bit_adapter ddc1;
struct i2c_bit_adapter ddc2;
}; };
#endif /* __MATROXFB_MAVEN_H__ */ #endif /* __MATROXFB_MAVEN_H__ */
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
* *
* (c) 1998,1999,2000,2001 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-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.65 2002/08/14
* *
* MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
* *
...@@ -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;
...@@ -226,7 +227,7 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p) { ...@@ -226,7 +227,7 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p) {
unsigned int wd; unsigned int wd;
unsigned int divider; unsigned int divider;
int i; int i;
int text = p->type == FB_TYPE_TEXT; int text = ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT;
int fwidth; int fwidth;
struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw);
...@@ -360,7 +361,8 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p) { ...@@ -360,7 +361,8 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p) {
((hd & 0x100) >> 7) | /* blanking */ ((hd & 0x100) >> 7) | /* blanking */
((hs & 0x100) >> 6) | /* sync start */ ((hs & 0x100) >> 6) | /* sync start */
(hbe & 0x040); /* end hor. blanking */ (hbe & 0x040); /* end hor. blanking */
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) /* FIXME: Enable vidrst only on G400, and only if TV-out is used */
if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1)
hw->CRTCEXT[1] |= 0x88; /* enable horizontal and vertical vidrst */ hw->CRTCEXT[1] |= 0x88; /* enable horizontal and vertical vidrst */
hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) | hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) |
((vd & 0x400) >> 8) | /* disp end */ ((vd & 0x400) >> 8) | /* disp end */
...@@ -872,7 +874,7 @@ static int parse_pins5(WPMINFO const struct matrox_bios* bd) { ...@@ -872,7 +874,7 @@ static int parse_pins5(WPMINFO const struct matrox_bios* bd) {
mult = bd->pins[4]?8000:6000; mult = bd->pins[4]?8000:6000;
MINFO->limits.pixel.vcomax = (bd->pins[ 38] == 0xFF) ? 600000 : bd->pins[ 38] * mult; MINFO->limits.pixel.vcomax = (bd->pins[ 38] == 0xFF) ? 600000 : bd->pins[ 38] * mult;
MINFO->limits.system.vcomax = (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 39] * mult; MINFO->limits.system.vcomax = (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 36] * mult;
MINFO->limits.video.vcomax = (bd->pins[ 37] == 0xFF) ? MINFO->limits.system.vcomax : bd->pins[ 37] * mult; MINFO->limits.video.vcomax = (bd->pins[ 37] == 0xFF) ? MINFO->limits.system.vcomax : bd->pins[ 37] * mult;
MINFO->limits.pixel.vcomin = (bd->pins[123] == 0xFF) ? 256000 : bd->pins[123] * mult; MINFO->limits.pixel.vcomin = (bd->pins[123] == 0xFF) ? 256000 : bd->pins[123] * mult;
MINFO->limits.system.vcomin = (bd->pins[121] == 0xFF) ? MINFO->limits.pixel.vcomin : bd->pins[121] * mult; MINFO->limits.system.vcomin = (bd->pins[121] == 0xFF) ? MINFO->limits.pixel.vcomin : bd->pins[121] * mult;
...@@ -1011,6 +1013,6 @@ EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */ ...@@ -1011,6 +1013,6 @@ EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */
EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */ EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */
EXPORT_SYMBOL(matroxfb_read_pins); EXPORT_SYMBOL(matroxfb_read_pins);
MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards"); MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
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