diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2002-08-16 02:56:25 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-08-16 02:56:25 -0700 |
| commit | 062dffeab2d2be6de87edcd7aaf5de807be995e5 (patch) | |
| tree | 0466aca36f5027a96df8ebd524d6bcf477e02889 | |
| parent | 273cbb5a2a76ec9ea0ec5d41fce802b3ba5c1361 (diff) | |
| parent | 75273dcb8350b929b1f34abb65e18ca7b45ab946 (diff) | |
Merge bk://matroxfb.bkbits.net/linux-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
| -rw-r--r-- | drivers/video/Config.help | 58 | ||||
| -rw-r--r-- | drivers/video/Config.in | 9 | ||||
| -rw-r--r-- | drivers/video/matrox/Makefile | 6 | ||||
| -rw-r--r-- | drivers/video/matrox/g450_pll.c | 85 | ||||
| -rw-r--r-- | drivers/video/matrox/g450_pll.h | 2 | ||||
| -rw-r--r-- | drivers/video/matrox/i2c-matroxfb.c | 259 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_DAC1064.c | 332 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_DAC1064.h | 4 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_Ti3026.c | 22 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_accel.c | 34 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_accel.h | 2 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_base.c | 608 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_base.h | 54 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_crtc2.c | 377 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_crtc2.h | 3 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_g450.c | 465 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_g450.h | 14 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_maven.c | 124 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_maven.h | 16 | ||||
| -rw-r--r-- | drivers/video/matrox/matroxfb_misc.c | 14 |
20 files changed, 1405 insertions, 1083 deletions
diff --git a/drivers/video/Config.help b/drivers/video/Config.help index 21c25f78749a..7a079fff6d58 100644 --- a/drivers/video/Config.help +++ b/drivers/video/Config.help @@ -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 diff --git a/drivers/video/Config.in b/drivers/video/Config.in index b90b2bff0615..b36afc2f81dd 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -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 diff --git a/drivers/video/matrox/Makefile b/drivers/video/matrox/Makefile index b7891f9cb540..fabb0e915aff 100644 --- a/drivers/video/matrox/Makefile +++ b/drivers/video/matrox/Makefile @@ -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 diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c index 2b7e81b08931..8073a73f6f35 100644 --- a/drivers/video/matrox/g450_pll.c +++ b/drivers/video/matrox/g450_pll.c @@ -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"); diff --git a/drivers/video/matrox/g450_pll.h b/drivers/video/matrox/g450_pll.h index 58a80ef2fd76..c17ed74501e9 100644 --- a/drivers/video/matrox/g450_pll.h +++ b/drivers/video/matrox/g450_pll.h @@ -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__ */ diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c index 59fe2b984710..63d70448e783 100644 --- a/drivers/video/matrox/i2c-matroxfb.c +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -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); diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c index 51aad5adb819..4dbe47514057 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.c +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -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); diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h index 6136fd33a14b..6fb532aefb43 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.h +++ b/drivers/video/matrox/matroxfb_DAC1064.h @@ -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__ */ diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c index 57b37600a3cb..92d53ad93595 100644 --- a/drivers/video/matrox/matroxfb_Ti3026.c +++ b/drivers/video/matrox/matroxfb_Ti3026.c @@ -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 */ diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c index 817e45cfa078..cfcb8eb3df68 100644 --- a/drivers/video/matrox/matroxfb_accel.c +++ b/drivers/video/matrox/matroxfb_accel.c @@ -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; diff --git a/drivers/video/matrox/matroxfb_accel.h b/drivers/video/matrox/matroxfb_accel.h index ab757c8e5f57..15e5a94b1194 100644 --- a/drivers/video/matrox/matroxfb_accel.h +++ b/drivers/video/matrox/matroxfb_accel.h @@ -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); diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 9912fa946907..477039b3fb8b 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -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"); diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index 5ad1962a3d00..64980ccd5574 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -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 { diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index 7bc8aea94f8c..56c7c7a02583 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -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); diff --git a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h index e625053bc679..be8a81f4253d 100644 --- a/drivers/video/matrox/matroxfb_crtc2.h +++ b/drivers/video/matrox/matroxfb_crtc2.h @@ -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 diff --git a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c index f07d3b26209b..17f5f9236bf4 100644 --- a/drivers/video/matrox/matroxfb_g450.c +++ b/drivers/video/matrox/matroxfb_g450.c @@ -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); diff --git a/drivers/video/matrox/matroxfb_g450.h b/drivers/video/matrox/matroxfb_g450.h index e9e4acc1ef30..98e0ce6691df 100644 --- a/drivers/video/matrox/matroxfb_g450.h +++ b/drivers/video/matrox/matroxfb_g450.h @@ -1,12 +1,14 @@ #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__ */ diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 70e51e7e2d7e..02bc8d68378f 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -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); diff --git a/drivers/video/matrox/matroxfb_maven.h b/drivers/video/matrox/matroxfb_maven.h index 060aa0b81864..99eddec9f30c 100644 --- a/drivers/video/matrox/matroxfb_maven.h +++ b/drivers/video/matrox/matroxfb_maven.h @@ -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__ */ diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c index 49a00835203f..18518d53d099 100644 --- a/drivers/video/matrox/matroxfb_misc.c +++ b/drivers/video/matrox/matroxfb_misc.c @@ -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"); |
