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
Say Y here if you have a Matrox Millennium, Matrox Millennium II,
Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video,
Matrox G400, G450 or G550 card in your box. At this time, support for
the G-series digital output is almost non-existant.
Matrox G400, G450 or G550 card in your box.
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want).
......@@ -413,7 +412,7 @@ CONFIG_FB_MATROX_MYSTIQUE
packed pixel and 32 bpp packed pixel. You can also use font widths
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
video card. If you select "Advanced lowlevel driver options", you
should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed
......@@ -423,11 +422,35 @@ CONFIG_FB_MATROX_G100
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.
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
head into kernel, otherwise picture will be shown only on output you
are probably not using...
G450/G550 hardware can display TV picture only from secondary CRTC,
and it performs no scaling, so picture must have 525 or 625 lines.
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
This drivers creates I2C buses which are needed for accessing the
......@@ -470,27 +493,6 @@ CONFIG_FB_MATROX_MAVEN
painting procedures (the secondary head does not use acceleration
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
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
......
......@@ -130,14 +130,19 @@ if [ "$CONFIG_FB" = "y" ]; then
if [ "$CONFIG_FB_MATROX" != "n" ]; then
bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
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
dep_tristate ' Matrox I2C support' CONFIG_FB_MATROX_I2C $CONFIG_FB_MATROX $CONFIG_I2C_ALGOBIT
if [ "$CONFIG_FB_MATROX_G100" = "y" ]; then
dep_tristate ' G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C
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
fi
tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
......
......@@ -5,16 +5,16 @@
# All of the (potential) objects that export symbols.
# 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.
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_I2C) += i2c-matroxfb.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
......
......@@ -2,11 +2,11 @@
*
* Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
*
* (c) 2001 Petr Vandrovec <vandrove@vc.cvut.cz>
* (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
*
* Portions Copyright (c) 2001 Matrox Graphics Inc.
*
* Version: 1.62 2001/11/29
* Version: 1.64 2002/06/10
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
......@@ -33,6 +33,10 @@ static unsigned int g450_mnp2vco(CPMINFO unsigned int mnp) {
return (ACCESS_FBINFO(features).pll.ref_freq * n + (m >> 1)) / m;
}
unsigned int g450_mnp2f(CPMINFO unsigned int mnp) {
return g450_vco2f(mnp, g450_mnp2vco(PMINFO mnp));
}
static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
if (f2 < f1) {
f2 = f1 - f2;
......@@ -52,40 +56,42 @@ static unsigned int g450_nextpll(CPMINFO const struct matrox_pll_limits* pi, uns
m = (mnp >> 16) & 0xFF;
p = mnp & 0xFF;
if (m == 0 || m == 0xFF) {
if (m == 0) {
if (p & 0x40) {
return NO_MORE_MNP;
do {
if (m == 0 || m == 0xFF) {
if (m == 0) {
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 {
p = 0x40;
p |= 0x20;
}
tvco >>= 1;
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;
m = 9;
} else {
p |= 0x20;
m--;
}
m = 9;
} else {
m--;
}
n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
} while (n < 0x03 || n > 0x7A);
return (m << 16) | (n << 8) | p;
}
......@@ -219,7 +225,7 @@ static void updatehwstate_clk(struct matrox_hw_state* hw, unsigned int mnp, unsi
}
}
static inline void g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
if (g450_cmppll(PMINFO mnp, pll)) {
g450_setpll(PMINFO mnp, pll);
}
......@@ -385,10 +391,8 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
unsigned int vco;
unsigned int delta;
if ((mnp & 0xFF00) < 0x0300 || (mnp & 0xFF00) > 0x7A00) {
continue;
}
vco = g450_mnp2vco(PMINFO mnp);
#if 0
if (pll == M_VIDEO_PLL) {
unsigned int big, small;
......@@ -406,6 +410,7 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
continue;
}
}
#endif
delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
for (idx = mnpcount; idx > 0; idx--) {
/* == is important; due to nextpll algorithm we get
......@@ -426,7 +431,7 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
}
/* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
if (!mnpcount) {
return 1;
return -EBUSY;
}
{
unsigned long flags;
......@@ -435,15 +440,15 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
matroxfb_DAC_lock_irqsave(flags);
mnp = g450_checkcache(PMINFO ci, mnparray[0]);
if (mnp != NO_MORE_MNP) {
g450_setpll_cond(PMINFO mnp, pll);
matroxfb_g450_setpll_cond(PMINFO mnp, pll);
} else {
mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount);
g450_addcache(ci, mnparray[0], mnp);
}
updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll);
matroxfb_DAC_unlock_irqrestore(flags);
return mnp;
}
return 0;
}
/* It must be greater than number of possible PLL values.
......@@ -465,8 +470,10 @@ int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll) {
}
EXPORT_SYMBOL(matroxfb_g450_setclk);
EXPORT_SYMBOL(g450_mnp2f);
EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
MODULE_AUTHOR("(c) 2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
MODULE_LICENSE("GPL");
......@@ -4,5 +4,7 @@
#include "matroxfb_base.h"
int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll);
unsigned int g450_mnp2f(CPMINFO unsigned int mnp);
void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll);
#endif /* __G450_PLL_H__ */
......@@ -2,9 +2,9 @@
*
* 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.
*
......@@ -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) {
unsigned long flags;
int v;
......@@ -40,7 +46,7 @@ static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
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;
int v;
......@@ -53,7 +59,7 @@ static inline void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int
}
/* 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)
state = 0;
else
......@@ -61,68 +67,24 @@ static void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state)
matroxfb_set_gpio(minfo, ~mask, state);
}
static void matroxfb_maven_setsda(void* data, int state) {
matroxfb_i2c_set(data, MAT_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_gpio_setsda(void* data, int state) {
struct i2c_bit_adapter* b = data;
matroxfb_i2c_set(b->minfo, b->mask.data, state);
}
static void matroxfb_ddc2_setsda(void* data, int state) {
matroxfb_i2c_set(data, DDC2_DATA, state);
static void matroxfb_gpio_setscl(void* data, int 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) {
matroxfb_i2c_set(data, DDC2_CLK, state);
static int matroxfb_gpio_getsda(void* data) {
struct i2c_bit_adapter* b = data;
return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0;
}
static int matroxfb_ddc2_getsda(void* data) {
return (matroxfb_read_gpio(data) & DDC2_DATA) ? 1 : 0;
}
static int matroxfb_ddc2_getscl(void* data) {
return (matroxfb_read_gpio(data) & DDC2_CLK) ? 1 : 0;
static int matroxfb_gpio_getscl(void* data) {
struct i2c_bit_adapter* b = data;
return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0;
}
static void matroxfb_dh_inc_use(struct i2c_adapter* dummy) {
......@@ -133,97 +95,36 @@ static void matroxfb_dh_dec_use(struct i2c_adapter* dummy) {
MOD_DEC_USE_COUNT;
}
static struct i2c_adapter matroxmaven_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 =
static struct i2c_adapter matrox_i2c_adapter_template =
{
NULL,
matroxfb_ddc1_setsda,
matroxfb_ddc1_setscl,
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,
.id = I2C_HW_B_G400,
.inc_use = matroxfb_dh_inc_use,
.dec_use = matroxfb_dh_dec_use,
};
static struct i2c_algo_bit_data matrox_ddc2_algo_template =
static struct i2c_algo_bit_data matrox_i2c_algo_template =
{
NULL,
matroxfb_ddc2_setsda,
matroxfb_ddc2_setscl,
matroxfb_ddc2_getsda,
matroxfb_ddc2_getscl,
matroxfb_gpio_setsda,
matroxfb_gpio_setscl,
matroxfb_gpio_getsda,
matroxfb_gpio_getscl,
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;
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->bac.data = minfo;
b->bac = matrox_i2c_algo_template;
b->bac.data = b;
err = i2c_bit_add_bus(&b->adapter);
b->initialized = !err;
return err;
......@@ -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) {
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) {
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) {
i2c_bit_bus_del(&minfo2->ddc2);
}
......@@ -299,24 +164,26 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
matroxfb_DAC_unlock_irqrestore(flags);
memset(m2info, 0, sizeof(*m2info));
m2info->maven.minfo = m2info;
m2info->ddc1.minfo = m2info;
m2info->ddc2.minfo = m2info;
m2info->primary_dev = minfo;
if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2064W ||
ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W ||
ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W_AGP)
err = i2c_ddc1b_init(m2info);
else
err = i2c_ddc1_init(m2info);
switch (ACCESS_FBINFO(chip)) {
case MGA_2064:
case MGA_2164:
err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0 on i2c-matroxfb");
break;
default:
err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0 on i2c-matroxfb");
break;
}
if (err)
goto fail_ddc1;
if (ACCESS_FBINFO(devflags.maven_capable)) {
err = i2c_ddc2_init(m2info);
if (err)
if (ACCESS_FBINFO(devflags.dualhead)) {
err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1 on i2c-matroxfb");
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");
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)
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) {
}
static struct matroxfb_driver i2c_matroxfb = {
LIST_HEAD_INIT(i2c_matroxfb.node),
"i2c-matroxfb",
i2c_matroxfb_probe,
i2c_matroxfb_remove,
.node = LIST_HEAD_INIT(i2c_matroxfb.node),
.name = "i2c-matroxfb",
.probe = i2c_matroxfb_probe,
.remove = i2c_matroxfb_remove,
};
static int __init i2c_matroxfb_init(void) {
......@@ -355,7 +222,7 @@ static void __exit i2c_matroxfb_exit(void) {
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_init(i2c_matroxfb_init);
......
......@@ -2,11 +2,11 @@
*
* 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.
*
* Version: 1.62 2001/11/29
* Version: 1.65 2002/08/14
*
* See matroxfb_base.c for contributors.
*
......@@ -150,7 +150,7 @@ static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) {
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.set_font) = matroxfb_DAC1064_setfont;
return 0;
......@@ -161,37 +161,20 @@ static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsi
unsigned int p;
DBG("DAC1064_calcclock")
/* only for devices older than G450 */
fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
if (ACCESS_FBINFO(devflags.g450dac)) {
if (fvco <= 300000) /* 276-324 */
;
else if (fvco <= 400000) /* 378-438 */
p |= 0x08;
else if (fvco <= 550000) /* 540-567 */
p |= 0x10;
else if (fvco <= 690000) /* 675-695 */
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;
}
p = (1 << p) - 1;
if (fvco <= 100000)
;
else if (fvco <= 140000)
p |= 0x08;
else if (fvco <= 180000)
p |= 0x10;
else
p |= 0x18;
*post = p;
}
......@@ -293,31 +276,164 @@ static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) {
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) {
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
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_XOUTPUTCONN] = 0x01; /* output #1 enabled */
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
if (ACCESS_FBINFO(devflags.g450dac)) {
hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL2;
hw->DACreg[POS1064_XOUTPUTCONN] = 0x05; /* output #1 enabled; CRTC1 connected to output #2 */
} else {
if (ACCESS_FBINFO(devflags.g450dac)) {
hw->DACreg[POS1064_XPWRCTRL] = 0x1F; /* powerup everything */
hw->DACreg[POS1064_XOUTPUTCONN] = 0x00; /* disable outputs */
hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
switch (ACCESS_FBINFO(outputs[0]).src) {
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_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
}
} 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_XOUTPUTCONN] = 0x09; /* output #1 enabled; CRTC2 connected to output #2 */
} else if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
else
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
} else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
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_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
else
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
if ((ACCESS_FBINFO(output.ph) | ACCESS_FBINFO(output.sh)) & MATROXFB_OUTPUT_CONN_PRIMARY)
hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE)
hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
}
}
void DAC1064_global_restore(WPMINFO2) {
......@@ -329,31 +445,32 @@ void DAC1064_global_restore(WPMINFO2) {
outDAC1064(PMINFO 0x20, 0x04);
outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type));
if (ACCESS_FBINFO(devflags.g450dac)) {
outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC); /* only matrox know... */
outDAC1064(PMINFO M1064_XPWRCTRL, 0x1F); /* powerup everything */
outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);
outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
outDAC1064(PMINFO M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
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);
DBG("DAC1064_init_1")
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_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP
| M1064_XMULCTRL_GRAPHICS_PALETIZED;
} else {
switch (p->var.bits_per_pixel) {
switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
/* case 4: not supported by MGA1064 DAC */
case 8:
hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
break;
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;
else
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) {
return 1; /* unsupported depth */
}
}
DAC1064_global_init(PMINFO2);
hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
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_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10;
hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18;
DAC1064_global_init(PMINFO2);
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);
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;
for (i = 0; i < 256; i++) {
......@@ -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 + 2] = i;
}
} else if (p->var.bits_per_pixel > 8) {
if (p->var.green.length == 5) { /* 0..31, 128..159 */
} else if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 8) {
if (ACCESS_FBINFO(fbcon).var.green.length == 5) { /* 0..31, 128..159 */
int i;
for (i = 0; i < 32; i++) {
......@@ -471,13 +588,8 @@ static void DAC1064_restore_2(WPMINFO struct display* p) {
#endif
}
static int m1064_compute(void* outdev, struct my_timming* m) {
#define minfo ((struct matrox_fb_info*)outdev)
#ifdef CONFIG_FB_MATROX_G450
if (ACCESS_FBINFO(devflags.g450dac)) {
matroxfb_g450_setclk(PMINFO m->pixclock, M_PIXEL_PLL_C);
} else
#endif
static int m1064_compute(void* out, struct my_timming* m) {
#define minfo ((struct matrox_fb_info*)out)
{
int i;
int tmout;
......@@ -504,37 +616,26 @@ static int m1064_compute(void* outdev, struct my_timming* m) {
return 0;
}
static int m1064_program(void* outdev) {
/* nothing, hardware is set in m1064_compute */
return 0;
}
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 struct matrox_altout m1064 = {
.name = "Primary output",
.compute = m1064_compute,
};
static int m1064_setmode(void* outdev, u_int32_t mode) {
if (mode != MATROXFB_OUTPUT_MODE_MONITOR)
return -EINVAL;
static int g450_compute(void* out, struct my_timming* m) {
#define minfo ((struct matrox_fb_info*)out)
if (m->mnp < 0) {
m->mnp = matroxfb_g450_setclk(PMINFO m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
if (m->mnp >= 0) {
m->pixclock = g450_mnp2f(PMINFO m->mnp);
}
}
#undef minfo
return 0;
}
static struct matrox_altout m1064 = {
m1064_compute,
m1064_program,
m1064_start,
m1064_incuse,
m1064_decuse,
m1064_setmode
static struct matrox_altout g450out = {
.name = "Primary output",
.compute = g450_compute,
};
#endif /* NEED_DAC1064 */
......@@ -545,7 +646,7 @@ static int MGA1064_init(WPMINFO struct my_timming* m, struct display* p) {
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;
hw->MiscOutReg = 0xCB;
......@@ -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 */
hw->CRTCEXT[3] |= 0x40;
if (DAC1064_init_2(PMINFO m, p)) return 1;
if (DAC1064_init_2(PMINFO m)) return 1;
return 0;
}
#endif
......@@ -567,7 +668,7 @@ static int MGAG100_init(WPMINFO struct my_timming* m, struct display* p) {
DBG("MGAG100_init")
if (DAC1064_init_1(PMINFO m, p)) return 1;
if (DAC1064_init_1(PMINFO m)) return 1;
hw->MXoptionReg &= ~0x2000;
if (matroxfb_vgaHWinit(PMINFO m, p)) return 1;
......@@ -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 */
hw->CRTCEXT[3] |= 0x40;
if (DAC1064_init_2(PMINFO m, p)) return 1;
if (DAC1064_init_2(PMINFO m)) return 1;
return 0;
}
#endif /* G100 */
......@@ -680,7 +781,10 @@ static int MGA1064_preinit(WPMINFO2) {
ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
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))
return 0; /* do not modify settings */
......@@ -726,8 +830,13 @@ static void g450_mclk_init(WPMINFO2) {
((ACCESS_FBINFO(values).reg.opt3 & 0x300000) == 0x300000)) {
matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.video), M_VIDEO_PLL);
} else {
/* slow down video clocks... */
matroxfb_g450_setclk(PMINFO 0, M_VIDEO_PLL);
unsigned long flags;
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);
......@@ -864,7 +973,14 @@ static int MGAG100_preinit(WPMINFO2) {
ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
? 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)) {
/* we must do this always, BIOS does not do it for us
......@@ -895,8 +1011,7 @@ static int MGAG100_preinit(WPMINFO2) {
hw->MXoptionReg |= 0x1080;
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
mga_outl(M_CTLWTST, 0x00000300);
/* mga_outl(M_CTLWTST, 0x03258A31); */
mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
udelay(100);
mga_outb(0x1C05, 0x00);
mga_outb(0x1C05, 0x80);
......@@ -947,17 +1062,18 @@ static int MGAG100_preinit(WPMINFO2) {
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
if (ACCESS_FBINFO(devflags.memtype) == -1)
ACCESS_FBINFO(devflags.memtype) = 0;
hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00;
else
hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
if (ACCESS_FBINFO(devflags.sgram))
hw->MXoptionReg |= 0x4000;
mga_outl(M_CTLWTST, 0x042450A1);
mga_outl(M_MEMRDBK, 0x00000108);
mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
udelay(200);
mga_outl(M_MACCESS, 0x00000000);
mga_outl(M_MACCESS, 0x00008000);
udelay(100);
mga_outl(M_MEMRDBK, 0x00000108);
mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
hw->MXoptionReg |= 0x00040020;
}
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
......
......@@ -146,6 +146,8 @@ void DAC1064_global_restore(WPMINFO2);
#define M1064_XPWRCTRL 0xA0
#define M1064_XPANMODE 0xA2
enum POS1064 {
POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL,
POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE,
......@@ -156,7 +158,7 @@ enum POS1064 {
POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST,
POS1064_XCRCBITSEL,
POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH,
POS1064_XOUTPUTCONN };
POS1064_XOUTPUTCONN, POS1064_XPANMODE, POS1064_XPWRCTRL };
#endif /* __MATROXFB_DAC1064_H__ */
......@@ -2,11 +2,11 @@
*
* 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.
*
* Version: 1.62 2000/11/29
* Version: 1.65 2002/08/14
*
* MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
*
......@@ -84,6 +84,7 @@
#include "matroxfb_Ti3026.h"
#include "matroxfb_misc.h"
#include "matroxfb_accel.h"
#include <linux/matroxfb.h>
#ifdef CONFIG_FB_MATROX_MILLENIUM
#define outTi3026 matroxfb_DAC_out
......@@ -401,7 +402,7 @@ static int matroxfb_ti3026_setfont(struct display* p, int width, int height) {
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.set_font) = matroxfb_ti3026_setfont;
return 0;
......@@ -433,7 +434,7 @@ static int Ti3026_setpclk(WPMINFO int clk, struct display* p) {
hw->DACclk[1] = pixfeed;
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->DACclk[3] = 0xFD;
hw->DACclk[4] = 0x3D;
......@@ -501,7 +502,7 @@ static int Ti3026_init(WPMINFO struct my_timming* m, struct display* p) {
DBG("Ti3026_init")
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_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
hw->DACreg[POS3026_XMUXCTRL] = TVP3026_XMUXCTRL_VGA;
......@@ -568,7 +569,7 @@ static int Ti3026_init(WPMINFO struct my_timming* m, struct display* p) {
/* set interleaving */
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 */
Ti3026_setpclk(PMINFO m->pixclock, p);
......@@ -811,6 +812,10 @@ static void Ti3026_reset(WPMINFO2) {
ti3026_ramdac_init(PMINFO2);
}
static struct matrox_altout ti3026_output = {
.name = "Primary output",
};
static int Ti3026_preinit(WPMINFO2) {
static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960,
1024, 1152, 1280, 1600, 1664, 1920,
......@@ -829,6 +834,11 @@ static int Ti3026_preinit(WPMINFO2) {
ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
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))
return 0;
/* preserve VGA I/O, BIOS and PPC */
......
......@@ -2,9 +2,9 @@
*
* 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>
*
......@@ -85,21 +85,21 @@
#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 mpitch;
u_int32_t mopmode;
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;
mpitch = (mpitch >> 4) | 0x8000; /* set something */
mopmode = M_OPMODE_8BPP;
} else {
switch (p->var.bits_per_pixel) {
switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
case 4: maccess = 0x00000000; /* accelerate as 8bpp video */
mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
mopmode = M_OPMODE_4BPP;
......@@ -107,7 +107,7 @@ void matrox_cfbX_init(WPMINFO struct display* p) {
case 8: maccess = 0x00000000;
mopmode = M_OPMODE_8BPP;
break;
case 16: if (p->var.green.length == 5)
case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5)
maccess = 0xC0000001;
else
maccess = 0x40000001;
......@@ -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) {
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;
}
......@@ -1040,7 +1040,7 @@ static int matrox_text_setfont(struct display* p, int width, int height) {
MINFO_FROM_DISP(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)
matrox_text_createcursor(PMINFO p);
......@@ -1144,11 +1144,11 @@ void initMatrox(WPMINFO struct display* p) {
if (p->dispsw && p->conp)
fb_con.con_cursor(p->conp, CM_ERASE);
p->dispsw_data = NULL;
if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
if (p->type == FB_TYPE_TEXT) {
if ((ACCESS_FBINFO(fbcon).var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
swtmp = &matroxfb_text;
} else {
switch (p->var.bits_per_pixel) {
switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4:
swtmp = &fbcon_cfb4;
......@@ -1183,10 +1183,10 @@ void initMatrox(WPMINFO struct display* p) {
}
}
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;
} else {
switch (p->var.bits_per_pixel) {
switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4:
swtmp = &matroxfb_cfb4;
......@@ -1222,8 +1222,8 @@ void initMatrox(WPMINFO struct display* p) {
}
memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw)));
p->dispsw = &ACCESS_FBINFO(dispsw);
if ((p->type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) {
ACCESS_FBINFO(hw_switch)->selhwcursor(PMINFO p);
if ((ACCESS_FBINFO(fbcon).fix.type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) {
ACCESS_FBINFO(hw_switch)->selhwcursor(PMINFO2);
}
}
......@@ -1233,7 +1233,7 @@ void matrox_init_putc(WPMINFO struct display* p, void (*dac_createcursor)(WPMINF
int i;
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_loadfont(PMINFO p);
i = 0;
......
......@@ -4,7 +4,7 @@
#include "matroxfb_base.h"
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 initMatrox(WPMINFO struct display* p);
......
......@@ -2,11 +2,11 @@
*
* 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.
*
* Version: 1.62 2001/11/29
* Version: 1.65 2002/08/14
*
* MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
*
......@@ -77,6 +77,15 @@
* "Uns Lider" <unslider@miranda.org>
* 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
* is included in this driver)
*
......@@ -100,6 +109,7 @@
#include "matroxfb_Ti3026.h"
#include "matroxfb_maven.h"
#include "matroxfb_crtc2.h"
#include "matroxfb_g450.h"
#include <linux/matroxfb.h>
#include <asm/uaccess.h>
......@@ -169,11 +179,13 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
if (ACCESS_FBINFO(dead))
return;
ACCESS_FBINFO(fbcon).var.xoffset = var->xoffset;
ACCESS_FBINFO(fbcon).var.yoffset = var->yoffset;
disp = ACCESS_FBINFO(currcon_display);
if (disp->type == FB_TYPE_TEXT) {
pos = var->yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(disp)?fontwidth(disp):8);
if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
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 {
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);
}
p0 = ACCESS_FBINFO(hw).CRTC[0x0D] = pos & 0xFF;
......@@ -212,6 +224,7 @@ static void matroxfb_remove(WPMINFO int dummy) {
}
matroxfb_unregister_device(MINFO);
unregister_framebuffer(&ACCESS_FBINFO(fbcon));
matroxfb_g450_shutdown(PMINFO2);
del_timer_sync(&ACCESS_FBINFO(cursor.timer));
#ifdef CONFIG_MTRR
if (ACCESS_FBINFO(mtrr.vram_valid))
......@@ -233,7 +246,7 @@ static void matroxfb_remove(WPMINFO int dummy) {
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")
if (ACCESS_FBINFO(dead)) {
......@@ -246,7 +259,7 @@ static int matroxfb_open(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")
if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) {
......@@ -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,
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")
......@@ -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)
{
#define minfo ((struct matrox_fb_info*)info)
#define minfo (container_of(info, struct matrox_fb_info, fbcon))
DBG("matroxfb_updatevar");
matrox_pan_var(PMINFO &fb_display[con].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) {
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 memlen;
DBG("matroxfb_decode_var")
switch (var->bits_per_pixel) {
switch (bpp) {
#ifdef FBCON_HAS_VGATEXT
case 0: if (!ACCESS_FBINFO(capable.text)) return -EINVAL;
break;
......@@ -438,22 +482,22 @@ static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screenin
var->yres_virtual = var->yres;
if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
if (var->bits_per_pixel) {
var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel);
memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
if (bpp) {
var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp);
memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
if (memlen > vramlen) {
var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp);
memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
}
/* There is hardware bug that no line can cross 4MB boundary */
/* give up for CFB24, it is impossible to easy workaround it */
/* for other try to do something */
if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) {
if (var->bits_per_pixel == 24) {
if (bpp == 24) {
/* sorry */
} else {
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 max_yres;
......@@ -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)
var->yoffset = var->yres_virtual - var->yres;
if (var->bits_per_pixel == 0) {
var->red.offset = 0;
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;
if (bpp == 16 && var->green.length == 5) {
bpp--; /* an artifical value - 15 */
}
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);
dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
var->xres_virtual, var->yres_virtual);
......@@ -589,9 +572,8 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *fb_info)
{
struct display* p;
#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
DBG("matroxfb_setcolreg")
......@@ -611,18 +593,17 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
ACCESS_FBINFO(palette[regno].blue) = blue;
ACCESS_FBINFO(palette[regno].transp) = transp;
p = ACCESS_FBINFO(currcon_display);
if (p->var.grayscale) {
if (ACCESS_FBINFO(fbcon).var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
}
red = CNVT_TOHW(red, p->var.red.length);
green = CNVT_TOHW(green, p->var.green.length);
blue = CNVT_TOHW(blue, p->var.blue.length);
transp = CNVT_TOHW(transp, p->var.transp.length);
red = CNVT_TOHW(red, ACCESS_FBINFO(fbcon).var.red.length);
green = CNVT_TOHW(green, ACCESS_FBINFO(fbcon).var.green.length);
blue = CNVT_TOHW(blue, ACCESS_FBINFO(fbcon).var.blue.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)
#ifdef FBCON_HAS_VGATEXT
case 0:
......@@ -642,87 +623,54 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
#ifdef FBCON_HAS_CFB16
case 16:
ACCESS_FBINFO(cmap.cfb16[regno]) =
(red << p->var.red.offset) |
(green << p->var.green.offset) |
(blue << p->var.blue.offset) |
(transp << p->var.transp.offset); /* for 1:5:5:5 */
(red << ACCESS_FBINFO(fbcon).var.red.offset) |
(green << ACCESS_FBINFO(fbcon).var.green.offset) |
(blue << ACCESS_FBINFO(fbcon).var.blue.offset) |
(transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* for 1:5:5:5 */
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
ACCESS_FBINFO(cmap.cfb24[regno]) =
(red << p->var.red.offset) |
(green << p->var.green.offset) |
(blue << p->var.blue.offset);
(red << ACCESS_FBINFO(fbcon).var.red.offset) |
(green << ACCESS_FBINFO(fbcon).var.green.offset) |
(blue << ACCESS_FBINFO(fbcon).var.blue.offset);
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
ACCESS_FBINFO(cmap.cfb32[regno]) =
(red << p->var.red.offset) |
(green << p->var.green.offset) |
(blue << p->var.blue.offset) |
(transp << p->var.transp.offset); /* 8:8:8:8 */
(red << ACCESS_FBINFO(fbcon).var.red.offset) |
(green << ACCESS_FBINFO(fbcon).var.green.offset) |
(blue << ACCESS_FBINFO(fbcon).var.blue.offset) |
(transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* 8:8:8:8 */
break;
#endif
}
return 0;
}
static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info)
static void matroxfb_update_fix(WPMINFO2)
{
struct display* p;
struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).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");
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->type = p->type;
fix->type_aux = p->type_aux;
fix->visual = p->visual;
fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
fix->ypanstep = 1;
fix->ywrapstep = 0;
fix->line_length = p->line_length;
fix->mmio_start = ACCESS_FBINFO(mmio.base);
fix->mmio_len = ACCESS_FBINFO(mmio.len);
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,
struct fb_info *info)
{
#define minfo ((struct matrox_fb_info*)info)
#define minfo (container_of(info, struct matrox_fb_info, fbcon))
int err;
int visual;
int cmap_len;
......@@ -763,17 +711,19 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
display->var = *var;
/* cmap */
ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
display->visual = visual;
display->ypanstep = 1;
display->ywrapstep = 0;
if (var->bits_per_pixel) {
display->type = FB_TYPE_PACKED_PIXELS;
display->type_aux = 0;
display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
} else {
display->type = FB_TYPE_TEXT;
display->type_aux = ACCESS_FBINFO(devflags.text_type_aux);
display->next_line = display->line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep);
if (display == ACCESS_FBINFO(currcon_display)) {
ACCESS_FBINFO(fbcon).var = *var;
matroxfb_update_fix(PMINFO2);
ACCESS_FBINFO(fbcon).fix.visual = visual;
if (var->bits_per_pixel) {
ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_PACKED_PIXELS;
ACCESS_FBINFO(fbcon).fix.type_aux = 0;
display->next_line = ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
} else {
ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_TEXT;
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->inverse = ACCESS_FBINFO(devflags.inverse);
......@@ -788,7 +738,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
unsigned int pos;
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 */
ACCESS_FBINFO(curr.ydstorg.bytes) = 0;
ACCESS_FBINFO(curr.ydstorg.chunks) = 0;
......@@ -818,8 +768,10 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
{ struct my_timming mt;
struct matrox_hw_state* hw;
int out;
matroxfb_var2my(var, &mt);
mt.crtc = MATROXFB_SRC_CRTC1;
/* CRTC1 delays */
switch (var->bits_per_pixel) {
case 0: mt.delay = 31 + 0; break;
......@@ -834,8 +786,18 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
del_timer_sync(&ACCESS_FBINFO(cursor.timer));
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));
if (display->type == FB_TYPE_TEXT) {
if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
if (fontheight(display))
pos = var->yoffset / fontheight(display) * display->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(display)?fontwidth(display):8);
else
......@@ -849,39 +811,23 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
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));
if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
if (ACCESS_FBINFO(primout))
ACCESS_FBINFO(primout)->program(MINFO);
}
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
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));
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->program) {
ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
}
}
ACCESS_FBINFO(cursor.redraw) = 1;
if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
if (ACCESS_FBINFO(primout))
ACCESS_FBINFO(primout)->start(MINFO);
}
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));
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
ACCESS_FBINFO(outputs[out]).output->start) {
ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
}
}
matrox_cfbX_init(PMINFO display);
up_read(&ACCESS_FBINFO(altout).lock);
matrox_cfbX_init(PMINFO2);
my_install_cmap(PMINFO2);
}
}
......@@ -896,7 +842,7 @@ static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green,
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.
* Return != 0 for invalid regno.
......@@ -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,
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)
: fb_display + con;
......@@ -942,7 +888,7 @@ static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
{
unsigned int cmap_len;
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")
......@@ -982,18 +928,22 @@ static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank)
vblank->flags |= FB_VBLANK_HBLANKING;
if (sts1 & 8)
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->hcount = 0;
vblank->count = 0;
return 0;
}
static struct matrox_altout panellink_output = {
.name = "Panellink output",
};
static int matroxfb_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg, 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_ioctl")
if (ACCESS_FBINFO(dead)) {
......@@ -1016,80 +966,74 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
case MATROXFB_SET_OUTPUT_MODE:
{
struct matroxioc_output_mode mom;
struct matrox_altout *oproc;
int val;
if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
return -EFAULT;
if (mom.output >= sizeof(u_int32_t))
return -EINVAL;
switch (mom.output) {
case MATROXFB_OUTPUT_PRIMARY:
if (mom.mode != MATROXFB_OUTPUT_MODE_MONITOR)
return -EINVAL;
/* mode did not change... */
return 0;
case MATROXFB_OUTPUT_SECONDARY:
if (mom.output >= MATROXFB_MAX_OUTPUTS)
return -ENXIO;
down_read(&ACCESS_FBINFO(altout.lock));
oproc = ACCESS_FBINFO(outputs[mom.output]).output;
if (!oproc) {
val = -ENXIO;
} else if (!oproc->verifymode) {
if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
val = 0;
} else {
val = -EINVAL;
down_read(&ACCESS_FBINFO(altout.lock));
if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device))
val = ACCESS_FBINFO(altout.output)->setmode(ACCESS_FBINFO(altout.device), mom.mode);
up_read(&ACCESS_FBINFO(altout.lock));
if (val != 1)
return val;
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info);
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
}
} else {
val = oproc->verifymode(ACCESS_FBINFO(outputs[mom.output]).data, mom.mode);
}
if (!val) {
if (ACCESS_FBINFO(outputs[mom.output]).mode != mom.mode) {
ACCESS_FBINFO(outputs[mom.output]).mode = mom.mode;
val = 1;
}
}
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;
down_read(&ACCESS_FBINFO(crtc2.lock));
crtc2 = (struct matroxfb_dh_fb_info*)(ACCESS_FBINFO(crtc2.info));
crtc2 = ACCESS_FBINFO(crtc2.info);
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));
}
return 0;
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;
break;
}
return 0;
}
case MATROXFB_GET_OUTPUT_MODE:
{
struct matroxioc_output_mode mom;
struct matrox_altout *oproc;
int val;
if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
return -EFAULT;
if (mom.output >= sizeof(u_int32_t))
return -EINVAL;
switch (mom.output) {
case MATROXFB_OUTPUT_PRIMARY:
mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
break;
case MATROXFB_OUTPUT_SECONDARY:
val = -EINVAL;
down_read(&ACCESS_FBINFO(altout.lock));
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;
if (mom.output >= MATROXFB_MAX_OUTPUTS)
return -ENXIO;
down_read(&ACCESS_FBINFO(altout.lock));
oproc = ACCESS_FBINFO(outputs[mom.output]).output;
if (!oproc) {
val = -ENXIO;
} else {
mom.mode = ACCESS_FBINFO(outputs[mom.output]).mode;
val = 0;
}
up_read(&ACCESS_FBINFO(altout.lock));
if (val)
return val;
if (copy_to_user((struct matroxioc_output_mode*)arg, &mom, sizeof(mom)))
return -EFAULT;
return 0;
......@@ -1097,52 +1041,109 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
case MATROXFB_SET_OUTPUT_CONNECTION:
{
u_int32_t tmp;
int i;
int changes;
if (copy_from_user(&tmp, (u_int32_t*)arg, sizeof(tmp)))
return -EFAULT;
if (tmp & ~ACCESS_FBINFO(output.all))
return -EINVAL;
if (tmp & ACCESS_FBINFO(output.sh))
return -EINVAL;
if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
return -EINVAL;
if (ACCESS_FBINFO(output.sh))
return -EINVAL;
for (i = 0; i < 32; i++) {
if (tmp & (1 << i)) {
if (i >= MATROXFB_MAX_OUTPUTS)
return -ENXIO;
if (!ACCESS_FBINFO(outputs[i]).output)
return -ENXIO;
switch (ACCESS_FBINFO(outputs[i]).src) {
case MATROXFB_SRC_NONE:
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;
ACCESS_FBINFO(output.ph) = tmp;
matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info);
return 0;
}
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 0;
}
case MATROXFB_GET_AVAILABLE_OUTPUTS:
{
u_int32_t tmp;
tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.sh);
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
tmp &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
if (put_user(tmp, (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) {
switch (ACCESS_FBINFO(outputs[i]).src) {
case MATROXFB_SRC_NONE:
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 0;
}
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 0;
}
}
return -EINVAL;
return -ENOTTY;
#undef minfo
}
......@@ -1150,7 +1151,7 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
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 crtc;
CRITFLAGS
......@@ -1184,8 +1185,6 @@ static struct fb_ops matroxfb_ops = {
.owner = THIS_MODULE,
.fb_open = matroxfb_open,
.fb_release = matroxfb_release,
.fb_get_fix = matroxfb_get_fix,
.fb_get_var = matroxfb_get_var,
.fb_set_var = matroxfb_set_var,
.fb_get_cmap = matroxfb_get_cmap,
.fb_set_cmap = matroxfb_set_cmap,
......@@ -1197,7 +1196,7 @@ static struct fb_ops matroxfb_ops = {
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 display *p;
......@@ -1392,10 +1391,10 @@ static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4
#define DEVF_VIDEO64BIT 0x0001
#define DEVF_SWAPS 0x0002
#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_TEXT4B 0x0020
#define DEVF_DDC_8_2 0x0040
/* #define DEVF_recycled 0x0040 */
/* #define DEVF_recycled 0x0080 */
#define DEVF_SUPPORT32MB 0x0100
#define DEVF_ANY_VXRES 0x0200
......@@ -1405,14 +1404,14 @@ static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4
#define DEVF_PANELLINK_CAPABLE 0x2000
#define DEVF_G450DAC 0x4000
#define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2)
#define DEVF_G2CORE (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG)
#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 | DEVF_DUALHEAD)
#define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */
#define DEVF_G200 (DEVF_G2CORE)
#define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
/* 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_G550 (DEVF_G450 | DEVF_BOTHDACS)
#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)
static struct board {
unsigned short vendor, device, rev, svid, sid;
......@@ -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;
}
#ifdef CONFIG_FB_MATROX_32MB
ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
ACCESS_FBINFO(devflags.support32MB) = (b->flags & DEVF_SUPPORT32MB) != 0;
#endif
ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
ACCESS_FBINFO(devflags.crtc2) = b->flags & DEVF_CRTC2;
ACCESS_FBINFO(devflags.maven_capable) = b->flags & DEVF_MAVEN_CAPABLE;
ACCESS_FBINFO(devflags.crtc2) = (b->flags & DEVF_CRTC2) != 0;
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) {
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_DFP;
ACCESS_FBINFO(outputs[2]).data = MINFO;
ACCESS_FBINFO(outputs[2]).output = &panellink_output;
if (dfp)
ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_DFP;
}
if (b->flags & DEVF_BOTHDACS) {
#ifdef CONFIG_FB_MATROX_G450
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
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(outputs[2]).src = MATROXFB_SRC_CRTC1;
else
ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
ACCESS_FBINFO(devflags.panellink) = 1;
}
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.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
......@@ -1732,6 +1728,7 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){
if (!ACCESS_FBINFO(devflags.novga))
request_region(0x3C0, 32, "matrox");
matroxfb_g450_connect(PMINFO2);
ACCESS_FBINFO(hw_switch->reset(PMINFO2));
ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
......@@ -1885,6 +1882,7 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){
}
return 0;
failVideoIO:;
matroxfb_g450_shutdown(PMINFO2);
mga_iounmap(ACCESS_FBINFO(video.vbase));
failCtrlIO:;
mga_iounmap(ACCESS_FBINFO(mmio.vbase));
......@@ -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(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);
if (!err) {
#ifndef CONFIG_FB_MATROX_MULTIHEAD
......@@ -2489,8 +2483,8 @@ int __init matroxfb_init(void)
/* *************************** init module code **************************** */
MODULE_AUTHOR("(c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450");
MODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550");
MODULE_LICENSE("GPL");
MODULE_PARM(mem, "i");
......
......@@ -2,7 +2,7 @@
*
* 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__
......@@ -288,6 +288,8 @@ static inline void mga_iounmap(vaddr_t va) {
struct my_timming {
unsigned int pixclock;
int mnp;
unsigned int crtc;
unsigned int HDisplay;
unsigned int HSyncStart;
unsigned int HSyncEnd;
......@@ -364,6 +366,10 @@ struct mavenregs {
u_int16_t hcorr;
};
struct matrox_crtc2 {
u_int32_t ctl;
};
struct matrox_hw_state {
u_int32_t MXoptionReg;
unsigned char DACclk[6];
......@@ -381,10 +387,7 @@ struct matrox_hw_state {
/* TVOut only */
struct mavenregs maven;
/* CRTC2 only */
/* u_int32_t TBD */
unsigned int vidclk;
struct matrox_crtc2 crtc2;
};
struct matrox_accel_data {
......@@ -396,15 +399,17 @@ struct matrox_accel_data {
};
struct matrox_altout {
const char *name;
int (*compute)(void* altout_dev, struct my_timming* input);
int (*program)(void* altout_dev);
int (*start)(void* altout_dev);
void (*incuse)(void* altout_dev);
void (*decuse)(void* altout_dev);
int (*setmode)(void* altout_dev, u_int32_t mode);
int (*getmode)(void* altout_dev, u_int32_t* mode);
int (*verifymode)(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 };
struct matrox_bios {
......@@ -421,9 +426,9 @@ struct matrox_bios {
struct matrox_switch;
struct matroxfb_driver;
struct matroxfb_dh_fb_info;
struct matrox_fb_info {
/* fb_info must be first */
struct fb_info fbcon;
struct list_head next_fb;
......@@ -439,20 +444,25 @@ struct matrox_fb_info {
struct pci_dev* pcidev;
struct {
u_int32_t all;
u_int32_t ph;
u_int32_t sh;
} output;
struct matrox_altout* primout;
unsigned int pixclock;
int mnp;
} crtc1;
struct {
struct fb_info* info;
unsigned int pixclock;
int mnp;
struct matroxfb_dh_fb_info* info;
struct rw_semaphore lock;
} crtc2;
struct {
struct matrox_altout* output;
void* device;
struct rw_semaphore lock;
struct rw_semaphore lock;
} 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
struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]);
......@@ -541,6 +551,8 @@ struct matrox_fb_info {
int memtype;
int g450dac;
int dfp_type;
int panellink; /* G400 DFP possible (not G450/G550) */
int dualhead;
unsigned int fbResource;
} devflags;
struct display_switch dispsw;
......@@ -618,7 +630,7 @@ struct matrox_fb_info {
#define PMINFO PMINFO2 ,
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),
......@@ -658,7 +670,7 @@ struct matrox_switch {
void (*reset)(WPMINFO2);
int (*init)(WPMINFO struct my_timming*, struct display*);
void (*restore)(WPMINFO struct display*);
int (*selhwcursor)(WPMINFO struct display*);
int (*selhwcursor)(WPMINFO2);
};
struct matroxfb_driver {
......
......@@ -2,11 +2,11 @@
*
* 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.
*
* 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)");
static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
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)
return 1;
*red = m2info->palette[regno].red;
......@@ -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,
unsigned blue, unsigned transp, struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info)
struct display* p;
#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
if (regno >= 16)
return 1;
......@@ -50,33 +49,32 @@ static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
m2info->palette[regno].blue = blue;
m2info->palette[regno].green = green;
m2info->palette[regno].transp = transp;
p = m2info->currcon_display;
if (p->var.grayscale) {
if (m2info->fbcon.var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
}
red = CNVT_TOHW(red, p->var.red.length);
green = CNVT_TOHW(green, p->var.green.length);
blue = CNVT_TOHW(blue, p->var.blue.length);
transp = CNVT_TOHW(transp, p->var.transp.length);
red = CNVT_TOHW(red, m2info->fbcon.var.red.length);
green = CNVT_TOHW(green, m2info->fbcon.var.green.length);
blue = CNVT_TOHW(blue, m2info->fbcon.var.blue.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
case 16:
m2info->cmap.cfb16[regno] =
(red << p->var.red.offset) |
(green << p->var.green.offset) |
(blue << p->var.blue.offset) |
(transp << p->var.transp.offset);
(red << m2info->fbcon.var.red.offset) |
(green << m2info->fbcon.var.green.offset) |
(blue << m2info->fbcon.var.blue.offset) |
(transp << m2info->fbcon.var.transp.offset);
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
m2info->cmap.cfb32[regno] =
(red << p->var.red.offset) |
(green << p->var.green.offset) |
(blue << p->var.blue.offset) |
(transp << p->var.transp.offset);
(red << m2info->fbcon.var.red.offset) |
(green << m2info->fbcon.var.green.offset) |
(blue << m2info->fbcon.var.blue.offset) |
(transp << m2info->fbcon.var.transp.offset);
break;
#endif
}
......@@ -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,
struct my_timming* mt,
struct display* p,
int mode,
unsigned int pos) {
u_int32_t tmp;
u_int32_t datactl;
MINFO_FROM(m2info->primary_dev);
switch (mode) {
......@@ -117,26 +115,26 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
tmp = 0x00800000;
break;
}
if (ACCESS_FBINFO(output.sh)) {
tmp |= 0x00000001; /* enable CRTC2 */
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
if (ACCESS_FBINFO(devflags.g450dac)) {
tmp |= 0x00000006; /* source from secondary pixel PLL */
/* no vidrst */
} else {
tmp |= 0x00000002; /* source from VDOCLK */
tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
/* MGA TVO is our clock source */
tmp |= 0x00000001; /* enable CRTC2 */
datactl = 0;
if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
if (ACCESS_FBINFO(devflags.g450dac)) {
tmp |= 0x00000006; /* source from secondary pixel PLL */
/* no vidrst when in monitor mode */
if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
tmp |= 0xC0001000; /* Enable H/V vidrst */
}
} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
tmp |= 0x00000004; /* source from pixclock */
/* PIXPLL is our clock source */
} else {
tmp |= 0x00000002; /* source from VDOCLK */
tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
/* MGA TVO is our clock source */
}
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY)
tmp |= 0x00100000; /* connect CRTC2 to DAC */
} else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
tmp |= 0x00000004; /* source from pixclock */
/* PIXPLL is our clock source */
}
if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
tmp |= 0x00100000; /* connect CRTC2 to DAC */
}
if (mt->interlaced) {
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,
mt->VSyncEnd >>= 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(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */
{
u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3);
if (mt->interlaced) {
u_int32_t linelen = m2info->fbcon.var.xres_virtual * (m2info->fbcon.var.bits_per_pixel >> 3);
if (tmp & 0x02000000) {
/* field #0 is smaller, so... */
mga_outl(0x3C2C, pos); /* field #1 vmemory start */
mga_outl(0x3C28, pos + linelen); /* field #0 vmemory start */
linelen <<= 1;
m2info->interlaced = 1;
} else {
mga_outl(0x3C28, pos); /* vmemory start */
m2info->interlaced = 0;
}
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 */
if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
tmp |= 0x00000100;
if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
tmp |= 0x00000200;
mga_outl(0x3C44, tmp);
mga_outl(0x3C4C, 0); /* data control */
}
static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info,
struct display* p) {
static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
MINFO_FROM(m2info->primary_dev);
mga_outl(0x3C10, 0x00000004); /* disable CRTC2, CRTC1->DAC1, PLL as clock source */
ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004;
}
static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) {
/* no acceleration for secondary head... */
}
......@@ -182,23 +208,23 @@ static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info,
unsigned int pos;
unsigned int linelen;
unsigned int pixelsize;
MINFO_FROM(m2info->primary_dev);
#define minfo (m2info->primary_dev)
pixelsize = var->bits_per_pixel >> 3;
linelen = var->xres_virtual * pixelsize;
pos = var->yoffset * linelen + var->xoffset * pixelsize;
m2info->fbcon.var.xoffset = var->xoffset;
m2info->fbcon.var.yoffset = var->yoffset;
pixelsize = m2info->fbcon.var.bits_per_pixel >> 3;
linelen = m2info->fbcon.var.xres_virtual * pixelsize;
pos = m2info->fbcon.var.yoffset * linelen + m2info->fbcon.var.xoffset * pixelsize;
pos += m2info->video.offbase;
if (var->vmode & FB_VMODE_INTERLACED) {
if (m2info->interlaced) {
mga_outl(0x3C2C, pos);
mga_outl(0x3C28, pos + linelen);
} else {
mga_outl(0x3C28, pos);
}
#undef minfo
}
static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
struct display* p,
struct fb_var_screeninfo* var,
int *visual,
int *video_cmap_len,
......@@ -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) {
switch (p->var.bits_per_pixel) {
switch (m2info->fbcon.var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB16
case 16:
p->dispsw_data = m2info->cmap.cfb16;
......@@ -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) {
#define m2info ((struct matroxfb_dh_fb_info*)info)
#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
MINFO_FROM(m2info->primary_dev);
if (MINFO) {
......@@ -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) {
#define m2info ((struct matroxfb_dh_fb_info*)info)
#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
MINFO_FROM(m2info->primary_dev);
if (MINFO) {
......@@ -320,49 +346,24 @@ static int matroxfb_dh_release(struct fb_info* info, int user) {
#undef m2info
}
static int matroxfb_dh_get_fix(struct fb_fix_screeninfo* fix, int con,
struct fb_info* info) {
#define m2info ((struct matroxfb_dh_fb_info*)info)
struct display* p;
static void matroxfb_dh_update_fix(struct matroxfb_dh_fb_info *m2info) {
struct fb_fix_screeninfo *fix = &m2info->fbcon.fix;
if (con >= 0)
p = fb_display + con;
else
p = m2info->fbcon.disp;
memset(fix, 0, sizeof(*fix));
strcpy(fix->id, "MATROX DH");
fix->smem_start = m2info->video.base;
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->ywrapstep = 0;
fix->line_length = p->line_length;
fix->xpanstep = 8; /* TBD */
fix->mmio_start = m2info->mmio.base;
fix->mmio_len = m2info->mmio.len;
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,
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;
int chgvar;
int visual;
......@@ -375,7 +376,7 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
p = m2info->fbcon.disp;
else
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;
switch (var->activate & FB_ACTIVATE_MASK) {
case FB_ACTIVATE_TEST: return 0;
......@@ -396,13 +397,15 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
chgvar = 0;
p->var = *var;
/* cmap */
m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
p->visual = visual;
p->ypanstep = 1;
p->ywrapstep = 0;
p->type = FB_TYPE_PACKED_PIXELS;
p->type_aux = 0;
p->next_line = p->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
if (con == m2info->fbcon.currcon) {
m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
m2info->fbcon.var = *var;
m2info->fbcon.fix.visual = visual;
m2info->fbcon.fix.type = FB_TYPE_PACKED_PIXELS;
m2info->fbcon.fix.type_aux = 0;
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->inverse = 0; /* TBD */
initMatroxDH(m2info, p);
......@@ -411,47 +414,51 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
if (con == m2info->fbcon.currcon) {
struct my_timming mt;
unsigned int pos;
int out;
int cnt;
matroxfb_var2my(var, &mt);
matroxfb_var2my(&m2info->fbcon.var, &mt);
mt.crtc = MATROXFB_SRC_CRTC2;
/* CRTC2 delay */
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;
DAC1064_global_init(PMINFO2);
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
if (ACCESS_FBINFO(primout))
ACCESS_FBINFO(primout)->compute(MINFO, &mt);
cnt = 0;
down_read(&ACCESS_FBINFO(altout).lock);
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
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) {
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(crtc2).pixclock = mt.pixclock;
ACCESS_FBINFO(crtc2).mnp = mt.mnp;
up_read(&ACCESS_FBINFO(altout).lock);
if (cnt) {
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);
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
if (ACCESS_FBINFO(primout))
ACCESS_FBINFO(primout)->program(MINFO);
}
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
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);
down_read(&ACCESS_FBINFO(altout).lock);
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
ACCESS_FBINFO(outputs[out]).output->program) {
ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
}
}
if (ACCESS_FBINFO(output.sh) & 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));
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
ACCESS_FBINFO(outputs[out]).output->start) {
ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
}
}
matroxfb_dh_cfbX_init(m2info, p);
up_read(&ACCESS_FBINFO(altout).lock);
matroxfb_dh_cfbX_init(m2info);
my_install_cmap(m2info);
}
return 0;
......@@ -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,
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;
if (con < 0)
......@@ -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,
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;
if (con < 0)
......@@ -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,
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 ||
var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
return -EINVAL;
......@@ -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) */
vblank->vcount = mga_inl(0x3C48) & 0x000007FF;
/* compatibility stuff */
if (vblank->vcount >= m2info->currcon_display->var.yres)
if (vblank->vcount >= m2info->fbcon.var.yres)
vblank->flags |= FB_VBLANK_VBLANKING;
return 0;
}
......@@ -536,7 +543,7 @@ static int matroxfb_dh_ioctl(struct inode* inode,
unsigned long arg,
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))
MINFO_FROM(m2info->primary_dev);
DBG("matroxfb_crtc2_ioctl")
......@@ -563,49 +570,95 @@ static int matroxfb_dh_ioctl(struct inode* inode,
case MATROXFB_SET_OUTPUT_CONNECTION:
{
u_int32_t tmp;
int out;
int changes;
if (get_user(tmp, (u_int32_t*)arg))
return -EFAULT;
if (tmp & ~ACCESS_FBINFO(output.all))
return -EINVAL;
if (tmp & ACCESS_FBINFO(output.ph))
return -EINVAL;
if (tmp & MATROXFB_OUTPUT_CONN_DFP)
return -EINVAL;
if ((ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) && tmp)
return -EINVAL;
if (tmp == ACCESS_FBINFO(output.sh))
for (out = 0; out < 32; out++) {
if (tmp & (1 << out)) {
if (out >= MATROXFB_MAX_OUTPUTS)
return -ENXIO;
if (!ACCESS_FBINFO(outputs[out]).output)
return -ENXIO;
switch (ACCESS_FBINFO(outputs[out]).src) {
case MATROXFB_SRC_NONE:
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;
ACCESS_FBINFO(output.sh) = tmp;
matroxfb_dh_switch(m2info->fbcon.currcon, info);
return 0;
}
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 0;
}
case MATROXFB_GET_AVAILABLE_OUTPUTS:
{
u_int32_t tmp;
/* we do not support DFP from CRTC2 */
tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph) & ~MATROXFB_OUTPUT_CONN_DFP;
/* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
tmp = 0;
u_int32_t tmp = 0;
int out;
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (ACCESS_FBINFO(outputs[out]).output) {
switch (ACCESS_FBINFO(outputs[out]).src) {
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))
return -EFAULT;
return 0;
}
}
return -EINVAL;
return -ENOTTY;
#undef m2info
}
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) {
case 1:
case 2:
......@@ -622,8 +675,6 @@ static struct fb_ops matroxfb_dh_ops = {
.owner = THIS_MODULE,
.fb_open = matroxfb_dh_open,
.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_get_cmap = matroxfb_dh_get_cmap,
.fb_set_cmap = matroxfb_dh_set_cmap,
......@@ -634,7 +685,7 @@ static struct fb_ops matroxfb_dh_ops = {
};
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 display* p;
......@@ -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) {
#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);
return 0;
#undef 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 ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) &&
!(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) &&
!(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) {
ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY;
ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP;
if (ACCESS_FBINFO(outputs[1]).output &&
ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_NONE &&
ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_NONE) {
ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC2;
}
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) {
}
down_write(&ACCESS_FBINFO(crtc2.lock));
oldcrtc2 = ACCESS_FBINFO(crtc2.info);
ACCESS_FBINFO(crtc2.info) = &m2info->fbcon;
ACCESS_FBINFO(crtc2.info) = m2info;
up_write(&ACCESS_FBINFO(crtc2.lock));
if (oldcrtc2) {
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) {
#define minfo (m2info->primary_dev)
if (m2info->fbcon_registered) {
int id;
struct fb_info* crtc2;
struct matroxfb_dh_fb_info* crtc2;
down_write(&ACCESS_FBINFO(crtc2.lock));
crtc2 = ACCESS_FBINFO(crtc2.info);
if (crtc2 == &m2info->fbcon)
if (crtc2 == m2info)
ACCESS_FBINFO(crtc2.info) = NULL;
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",
crtc2, &m2info->fbcon);
crtc2, m2info);
printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n");
return;
}
......@@ -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) {
matroxfb_dh_deregisterfb(crtc2);
kfree(crtc2);
}
static struct matroxfb_driver crtc2 = {
......@@ -839,7 +890,7 @@ static void matroxfb_crtc2_exit(void) {
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_LICENSE("GPL");
module_init(matroxfb_crtc2_init);
......
......@@ -27,8 +27,9 @@ struct matroxfb_dh_fb_info {
unsigned int len;
} mmio;
int currcon;
struct display* currcon_display;
int interlaced:1;
union {
#ifdef FBCON_HAS_CFB16
......
......@@ -2,145 +2,418 @@
*
* 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.
*
* Version: 1.62 2001/11/29
* Version: 1.64 2002/06/02
*
* See matroxfb_base.c for contributors.
*
*/
#include "matroxfb_g450.h"
#include "matroxfb_base.h"
#include "matroxfb_misc.h"
#include "matroxfb_DAC1064.h"
#include "g450_pll.h"
#include <linux/matroxfb.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
#define m2info ((struct matroxfb_g450_info*)md)
#define minfo (m2info->primary_dev)
ACCESS_FBINFO(hw).vidclk = mt->pixclock;
#undef minfo
#undef m2info
return 0;
}
static void cve2_set_reg(WPMINFO int reg, int val) {
unsigned long flags;
static int matroxfb_g450_program(void* md) {
#define m2info ((struct matroxfb_g450_info*)md)
#define minfo (m2info->primary_dev)
matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(hw).vidclk, M_VIDEO_PLL);
#undef minfo
#undef m2info
return 0;
matroxfb_DAC_lock_irqsave(flags);
matroxfb_DAC_out(PMINFO 0x87, reg);
matroxfb_DAC_out(PMINFO 0x88, val);
matroxfb_DAC_unlock_irqrestore(flags);
}
static int matroxfb_g450_start(void* md) {
return 0;
}
struct output_desc {
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) {
MOD_INC_USE_COUNT;
}
static void computeRegs(WPMINFO struct mavenregs* r, struct my_timming* mt, const struct output_desc* outd) {
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) {
MOD_DEC_USE_COUNT;
dprintk(KERN_DEBUG "MNP=%08X\n", mnp);
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) {
if (arg == MATROXFB_OUTPUT_MODE_MONITOR) {
return 1;
static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
static const struct output_desc paloutd = {
.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) {
*arg = MATROXFB_OUTPUT_MODE_MONITOR;
return 0;
#define LR(x) cve2_set_reg(PMINFO (x), m->regs[(x)])
static void cve2_init_TV(WPMINFO const struct mavenregs* m) {
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 = {
matroxfb_g450_compute,
matroxfb_g450_program,
matroxfb_g450_start,
matroxfb_g450_incuse,
matroxfb_g450_decuse,
matroxfb_g450_set_mode,
matroxfb_g450_get_mode
};
static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
MINFO_FROM(md);
dprintk(KERN_DEBUG "Computing, mode=%u\n", ACCESS_FBINFO(outputs[1]).mode);
static int matroxfb_g450_connect(struct matroxfb_g450_info* m2info) {
MINFO_FROM(m2info->primary_dev);
if (mt->crtc == MATROXFB_SRC_CRTC2 &&
ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
const struct output_desc* outd;
down_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(altout.device) = m2info;
ACCESS_FBINFO(altout.output) = &matroxfb_g450_altout;
up_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), (struct fb_info*)MINFO);
cve2_init_TVdata(ACCESS_FBINFO(outputs[1]).mode, &ACCESS_FBINFO(hw).maven, &outd);
computeRegs(PMINFO &ACCESS_FBINFO(hw).maven, mt, outd);
} else if (mt->mnp < 0) {
/* We must program clocks before CRTC2, otherwise interlaced mode
startup may fail */
mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
}
dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
return 0;
}
static void matroxfb_g450_shutdown(struct matroxfb_g450_info* m2info) {
MINFO_FROM(m2info->primary_dev);
static int matroxfb_g450_program(void* md) {
MINFO_FROM(md);
if (MINFO) {
ACCESS_FBINFO(output.all) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
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;
if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
cve2_init_TV(PMINFO &ACCESS_FBINFO(hw).maven);
}
return 0;
}
/* we do not have __setup() yet */
static void* matroxfb_g450_probe(struct matrox_fb_info* minfo) {
struct matroxfb_g450_info* m2info;
/* hardware is not G450... */
if (!ACCESS_FBINFO(devflags.g450dac))
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;
static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
switch (arg) {
case MATROXFB_OUTPUT_MODE_PAL:
case MATROXFB_OUTPUT_MODE_NTSC:
case MATROXFB_OUTPUT_MODE_MONITOR:
return 0;
}
return m2info;
return -EINVAL;
}
static void matroxfb_g450_remove(struct matrox_fb_info* minfo, void* g450) {
matroxfb_g450_shutdown(g450);
kfree(g450);
static int g450_dvi_compute(void* md, struct my_timming* mt) {
MINFO_FROM(md);
if (mt->mnp < 0) {
mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
}
return 0;
}
static struct matroxfb_driver g450 = {
.name = "Matrox G450 output #2",
.probe = matroxfb_g450_probe,
.remove = matroxfb_g450_remove };
static struct matrox_altout matroxfb_g450_altout = {
.name = "Secondary output",
.compute = matroxfb_g450_compute,
.program = matroxfb_g450_program,
.verifymode = matroxfb_g450_verify_mode,
};
static int matroxfb_g450_init(void) {
matroxfb_register_driver(&g450);
return 0;
static struct matrox_altout matroxfb_g450_dvi = {
.name = "DVI output",
.compute = g450_dvi_compute,
};
void matroxfb_g450_connect(WPMINFO2) {
if (ACCESS_FBINFO(devflags.g450dac)) {
down_write(&ACCESS_FBINFO(altout.lock));
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) {
matroxfb_unregister_driver(&g450);
void matroxfb_g450_shutdown(WPMINFO2) {
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>");
MODULE_DESCRIPTION("Matrox G450 secondary output driver");
EXPORT_SYMBOL(matroxfb_g450_connect);
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_init(matroxfb_g450_init);
module_exit(matroxfb_g450_exit);
#ifndef __MATROXFB_G450_H__
#define __MATROXFB_G450_H__
#include <linux/ioctl.h>
#include "matroxfb_base.h"
struct matroxfb_g450_info {
struct matrox_fb_info* primary_dev;
unsigned int timmings;
};
#ifdef CONFIG_FB_MATROX_G450
void matroxfb_g450_connect(WPMINFO2);
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 @@
*
* 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.
*
* Version: 1.62 2001/11/29
* Version: 1.64 2002/06/10
*
* See matroxfb_base.c for contributors.
*
......@@ -22,18 +22,12 @@
#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_C 2
struct maven_data {
struct matrox_fb_info* primary_head;
struct i2c_client* client;
int mode;
int version;
};
......@@ -127,7 +121,7 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
fwant = htotal * vtotal;
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);
for (p = 1; p <= pll->post_shift_max; p++) {
if (fwant * 2 > fmax)
......@@ -163,9 +157,9 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
ln = ln - scrlen;
if (ln > htotal)
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) {
printk(KERN_DEBUG "Better...\n");
dprintk(KERN_DEBUG "Better...\n");
*h2 = besth2 = ln;
*post = p;
*in = m;
......@@ -221,6 +215,13 @@ static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
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 struct mavenregs palregs = { {
0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
......@@ -273,7 +274,7 @@ static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* dat
0x3F, 0x03, /* 3C-3D */
0x00, /* 3E written multiple times */
0x00, /* 3F not written */
}, MODE_PAL, 625, 50 };
}, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
static struct mavenregs ntscregs = { {
0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
0x00,
......@@ -325,14 +326,16 @@ static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* dat
0x3C, 0x00, /* 3C-3D */
0x00, /* 3E written multiple times */
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;
else
*data = ntscregs;
data->regs[0x93] = 0xA2;
/* Set deflicker */
data->regs[0x93] = maven_compute_deflicker(md);
/* gamma correction registers */
data->regs[0x83] = 0x00;
......@@ -386,7 +389,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
LRP(0x17);
LR(0x0B);
LR(0x0C);
if (m->mode & MODE_PAL) {
if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
maven_set_reg(c, 0x35, 0x10); /* ... */
} else {
maven_set_reg(c, 0x35, 0x0F); /* ... */
......@@ -424,7 +427,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
LR(0x27);
LR(0x21);
LRP(0x2A);
if (m->mode & MODE_PAL)
if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
maven_set_reg(c, 0x35, 0x1D); /* ... */
else
maven_set_reg(c, 0x35, 0x1C);
......@@ -473,7 +476,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
LR(0xC2);
maven_get_reg(c, 0x8D);
maven_set_reg(c, 0x8D, 0x00);
maven_set_reg(c, 0x8D, 0x04);
LR(0x20); /* saturation #1 */
LR(0x22); /* saturation #2 */
......@@ -498,7 +501,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
LR(0x8B);
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);
LR(0x33);
......@@ -524,7 +527,7 @@ static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
LR(0x27);
LR(0x21);
LRP(0x2A);
if (m->mode & MODE_PAL)
if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
maven_set_reg(c, 0x35, 0x1D);
else
maven_set_reg(c, 0x35, 0x1C);
......@@ -562,7 +565,7 @@ static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
unsigned int a, b, c, h2;
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;
if (diff < err) {
......@@ -583,9 +586,10 @@ static inline int maven_compute_timming(struct maven_data* md,
struct mavenregs* m) {
unsigned int tmpi;
unsigned int a, bv, c;
MINFO_FROM(md->primary_head);
m->mode = md->mode;
if (MODE_TV(md->mode)) {
m->mode = ACCESS_FBINFO(outputs[1]).mode;
if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
unsigned int lmargin;
unsigned int umargin;
unsigned int vslen;
......@@ -804,7 +808,7 @@ static inline int maven_compute_timming(struct maven_data* md,
m->regs[0xB0] = 0x03; /* output: monitor */
m->regs[0xB1] = 0xA0; /* ??? */
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[0xBF] = 0x22; /* makes picture stable */
......@@ -815,7 +819,7 @@ static inline int maven_program_timming(struct maven_data* md,
const struct mavenregs* m) {
struct i2c_client* c = md->client;
if (m->mode & MODE_MONITOR) {
if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
LR(0x80);
LR(0x81);
LR(0x82);
......@@ -855,22 +859,16 @@ static inline int maven_resync(struct maven_data* md) {
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) {
case MATROXFB_OUTPUT_MODE_PAL:
case MATROXFB_OUTPUT_MODE_NTSC:
case MATROXFB_OUTPUT_MODE_MONITOR:
md->mode = arg;
return 1;
return 0;
}
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) {
......@@ -893,48 +891,31 @@ static int maven_out_start(void* md) {
return maven_resync(md);
}
static void maven_out_incuse(void* md) {
if (md)
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 int maven_out_verify_mode(void* md, u_int32_t arg) {
return maven_verify_output_mode(md, arg);
}
static struct matrox_altout maven_altout = {
maven_out_compute,
maven_out_program,
maven_out_start,
maven_out_incuse,
maven_out_decuse,
maven_out_set_mode,
maven_out_get_mode
.name = "Secondary output",
.compute = maven_out_compute,
.program = maven_out_program,
.start = maven_out_start,
.verifymode = maven_out_verify_mode,
};
static int maven_init_client(struct i2c_client* clnt) {
struct i2c_adapter* a = clnt->adapter;
struct maven_data* md = clnt->data;
struct matroxfb_dh_maven_info* m2info __attribute__((unused)) = ((struct i2c_bit_adapter*)a)->minfo;
MINFO_FROM(m2info->primary_dev);
MINFO_FROM(container_of(a, struct i2c_bit_adapter, adapter)->minfo);
md->mode = MODE_MONITOR;
md->primary_head = MINFO;
md->client = clnt;
down_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(altout.device) = md;
ACCESS_FBINFO(altout.output) = &maven_altout;
ACCESS_FBINFO(outputs[1]).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));
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
if (maven_get_reg(clnt, 0xB2) < 0x14) {
md->version = MGATVO_B;
} else {
......@@ -947,13 +928,14 @@ static int maven_shutdown_client(struct i2c_client* clnt) {
struct maven_data* md = clnt->data;
if (md->primary_head) {
md->primary_head->output.all &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
md->primary_head->output.ph &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
md->primary_head->output.sh &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
down_write(&md->primary_head->altout.lock);
md->primary_head->altout.device = NULL;
md->primary_head->altout.output = NULL;
up_write(&md->primary_head->altout.lock);
MINFO_FROM(md->primary_head);
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;
up_write(&ACCESS_FBINFO(altout.lock));
md->primary_head = NULL;
}
return 0;
......@@ -983,7 +965,7 @@ static int maven_detect_client(struct i2c_adapter* adapter, int address, unsigne
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_PROTOCOL_MANGLING))
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))) {
err = -ENOMEM;
goto ERROR0;
......@@ -1066,7 +1048,7 @@ static void matroxfb_maven_exit(void) {
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_LICENSE("GPL");
module_init(matroxfb_maven_init);
......
......@@ -6,21 +6,15 @@
#include <linux/i2c-algo-bit.h>
#include "matroxfb_base.h"
struct matroxfb_dh_maven_info;
struct i2c_bit_adapter {
struct i2c_adapter adapter;
int initialized;
struct i2c_algo_bit_data bac;
struct matroxfb_dh_maven_info *minfo;
};
struct matroxfb_dh_maven_info {
struct matrox_fb_info* primary_dev;
struct i2c_bit_adapter maven;
struct i2c_bit_adapter ddc1;
struct i2c_bit_adapter ddc2;
struct matrox_fb_info* minfo;
struct {
unsigned int data;
unsigned int clock;
} mask;
};
#endif /* __MATROXFB_MAVEN_H__ */
......@@ -2,11 +2,11 @@
*
* 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.
*
* Version: 1.62 2001/11/29
* Version: 1.65 2002/08/14
*
* 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) {
if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
mt->pixclock = 1000000000 / pixclock;
if (mt->pixclock < 1) mt->pixclock = 1;
mt->mnp = -1;
mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
mt->HDisplay = var->xres;
......@@ -226,7 +227,7 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p) {
unsigned int wd;
unsigned int divider;
int i;
int text = p->type == FB_TYPE_TEXT;
int text = ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT;
int fwidth;
struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw);
......@@ -360,7 +361,8 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p) {
((hd & 0x100) >> 7) | /* blanking */
((hs & 0x100) >> 6) | /* sync start */
(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[2] = ((vt & 0xC00) >> 10) |
((vd & 0x400) >> 8) | /* disp end */
......@@ -872,7 +874,7 @@ static int parse_pins5(WPMINFO const struct matrox_bios* bd) {
mult = bd->pins[4]?8000:6000;
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.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;
......@@ -1011,6 +1013,6 @@ EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */
EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */
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_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