Commit daf389a0 authored by Petr Vandrovec's avatar Petr Vandrovec

Use arrays for holding Matrox output drivers, it is nicer and more extensible

than current solution with per-CRTC bitmaps.
parent ca5d8440
...@@ -300,7 +300,7 @@ void DAC1064_global_init(WPMINFO2) { ...@@ -300,7 +300,7 @@ void DAC1064_global_init(WPMINFO2) {
hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN; hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL; hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
hw->DACreg[POS1064_XOUTPUTCONN] = 0x01; /* output #1 enabled */ hw->DACreg[POS1064_XOUTPUTCONN] = 0x01; /* output #1 enabled */
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) {
if (ACCESS_FBINFO(devflags.g450dac)) { if (ACCESS_FBINFO(devflags.g450dac)) {
hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL2; 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 */ hw->DACreg[POS1064_XOUTPUTCONN] = 0x05; /* output #1 enabled; CRTC1 connected to output #2 */
...@@ -308,15 +308,15 @@ void DAC1064_global_init(WPMINFO2) { ...@@ -308,15 +308,15 @@ void DAC1064_global_init(WPMINFO2) {
hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT; hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12; hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
} }
} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { } else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12; hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
hw->DACreg[POS1064_XOUTPUTCONN] = 0x09; /* output #1 enabled; CRTC2 connected to output #2 */ hw->DACreg[POS1064_XOUTPUTCONN] = 0x09; /* output #1 enabled; CRTC2 connected to output #2 */
} else if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) } else if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1)
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12; hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
else else
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS; hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
if ((ACCESS_FBINFO(output.ph) | ACCESS_FBINFO(output.sh)) & MATROXFB_OUTPUT_CONN_PRIMARY) if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE)
hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN; hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
} }
...@@ -505,6 +505,7 @@ static int m1064_compute(void* outdev, struct my_timming* m) { ...@@ -505,6 +505,7 @@ static int m1064_compute(void* outdev, struct my_timming* m) {
} }
static struct matrox_altout m1064 = { static struct matrox_altout m1064 = {
.name = "Primary output",
.compute = m1064_compute, .compute = m1064_compute,
}; };
...@@ -651,7 +652,10 @@ static int MGA1064_preinit(WPMINFO2) { ...@@ -651,7 +652,10 @@ static int MGA1064_preinit(WPMINFO2) {
ACCESS_FBINFO(features.accel.has_cacheflush) = 1; ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor; ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
ACCESS_FBINFO(primout) = &m1064; ACCESS_FBINFO(outputs[0]).output = &m1064;
ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
ACCESS_FBINFO(outputs[0]).data = MINFO;
ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
if (ACCESS_FBINFO(devflags.noinit)) if (ACCESS_FBINFO(devflags.noinit))
return 0; /* do not modify settings */ return 0; /* do not modify settings */
...@@ -835,7 +839,10 @@ static int MGAG100_preinit(WPMINFO2) { ...@@ -835,7 +839,10 @@ static int MGAG100_preinit(WPMINFO2) {
ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100 ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
? ACCESS_FBINFO(devflags.sgram) : 1; ? ACCESS_FBINFO(devflags.sgram) : 1;
ACCESS_FBINFO(primout) = &m1064; ACCESS_FBINFO(outputs[0]).output = &m1064;
ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
ACCESS_FBINFO(outputs[0]).data = MINFO;
ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
if (ACCESS_FBINFO(devflags.g450dac)) { if (ACCESS_FBINFO(devflags.g450dac)) {
/* we must do this always, BIOS does not do it for us /* we must do this always, BIOS does not do it for us
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* *
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
* *
* (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
* *
* Portions Copyright (c) 2001 Matrox Graphics Inc. * Portions Copyright (c) 2001 Matrox Graphics Inc.
* *
* Version: 1.62 2000/11/29 * Version: 1.64 2002/06/10
* *
* MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
* *
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
#include "matroxfb_Ti3026.h" #include "matroxfb_Ti3026.h"
#include "matroxfb_misc.h" #include "matroxfb_misc.h"
#include "matroxfb_accel.h" #include "matroxfb_accel.h"
#include <linux/matroxfb.h>
#ifdef CONFIG_FB_MATROX_MILLENIUM #ifdef CONFIG_FB_MATROX_MILLENIUM
#define outTi3026 matroxfb_DAC_out #define outTi3026 matroxfb_DAC_out
...@@ -811,6 +812,10 @@ static void Ti3026_reset(WPMINFO2) { ...@@ -811,6 +812,10 @@ static void Ti3026_reset(WPMINFO2) {
ti3026_ramdac_init(PMINFO2); ti3026_ramdac_init(PMINFO2);
} }
static struct matrox_altout ti3026_output = {
.name = "Primary output",
};
static int Ti3026_preinit(WPMINFO2) { static int Ti3026_preinit(WPMINFO2) {
static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960, static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960,
1024, 1152, 1280, 1600, 1664, 1920, 1024, 1152, 1280, 1600, 1664, 1920,
...@@ -829,6 +834,11 @@ static int Ti3026_preinit(WPMINFO2) { ...@@ -829,6 +834,11 @@ static int Ti3026_preinit(WPMINFO2) {
ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1; ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor; ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor;
ACCESS_FBINFO(outputs[0]).data = MINFO;
ACCESS_FBINFO(outputs[0]).output = &ti3026_output;
ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
if (ACCESS_FBINFO(devflags.noinit)) if (ACCESS_FBINFO(devflags.noinit))
return 0; return 0;
/* preserve VGA I/O, BIOS and PPC */ /* preserve VGA I/O, BIOS and PPC */
......
...@@ -793,6 +793,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, ...@@ -793,6 +793,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
{ struct my_timming mt; { struct my_timming mt;
struct matrox_hw_state* hw; struct matrox_hw_state* hw;
int out;
matroxfb_var2my(var, &mt); matroxfb_var2my(var, &mt);
/* CRTC1 delays */ /* CRTC1 delays */
...@@ -809,6 +810,14 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, ...@@ -809,6 +810,14 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
del_timer_sync(&ACCESS_FBINFO(cursor.timer)); del_timer_sync(&ACCESS_FBINFO(cursor.timer));
ACCESS_FBINFO(cursor.state) = CM_ERASE; ACCESS_FBINFO(cursor.state) = CM_ERASE;
down_read(&ACCESS_FBINFO(altout).lock);
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
ACCESS_FBINFO(outputs[out]).output->compute) {
ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
}
}
up_read(&ACCESS_FBINFO(altout).lock);
ACCESS_FBINFO(hw_switch->init(PMINFO &mt, display)); ACCESS_FBINFO(hw_switch->init(PMINFO &mt, display));
if (display->type == FB_TYPE_TEXT) { if (display->type == FB_TYPE_TEXT) {
if (fontheight(display)) if (fontheight(display))
...@@ -824,38 +833,22 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, ...@@ -824,38 +833,22 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
hw->CRTC[0x0C] = (pos & 0xFF00) >> 8; hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
hw->CRTCEXT[8] = pos >> 21; hw->CRTCEXT[8] = pos >> 21;
if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
if (ACCESS_FBINFO(primout) && ACCESS_FBINFO(primout)->compute)
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.output)->compute(ACCESS_FBINFO(altout.device), &mt);
up_read(&ACCESS_FBINFO(altout.lock));
}
ACCESS_FBINFO(hw_switch->restore(PMINFO display)); ACCESS_FBINFO(hw_switch->restore(PMINFO display));
if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) { down_read(&ACCESS_FBINFO(altout).lock);
if (ACCESS_FBINFO(primout) && ACCESS_FBINFO(primout)->program) for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
ACCESS_FBINFO(primout)->program(MINFO); if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
} ACCESS_FBINFO(outputs[out]).output->program) {
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
down_read(&ACCESS_FBINFO(altout.lock)); }
if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.output)->program)
ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device));
up_read(&ACCESS_FBINFO(altout.lock));
} }
ACCESS_FBINFO(cursor.redraw) = 1; ACCESS_FBINFO(cursor.redraw) = 1;
if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) { for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (ACCESS_FBINFO(primout) && ACCESS_FBINFO(primout)->start) if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
ACCESS_FBINFO(primout)->start(MINFO); ACCESS_FBINFO(outputs[out]).output->start) {
} ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { }
down_read(&ACCESS_FBINFO(altout.lock));
if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.output)->start)
ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
up_read(&ACCESS_FBINFO(altout.lock));
} }
up_read(&ACCESS_FBINFO(altout).lock);
matrox_cfbX_init(PMINFO display); matrox_cfbX_init(PMINFO display);
my_install_cmap(PMINFO2); my_install_cmap(PMINFO2);
} }
...@@ -964,6 +957,10 @@ static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank) ...@@ -964,6 +957,10 @@ static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank)
return 0; return 0;
} }
static struct matrox_altout panellink_output = {
.name = "Panellink output",
};
static int matroxfb_ioctl(struct inode *inode, struct file *file, static int matroxfb_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg, int con, unsigned int cmd, unsigned long arg, int con,
struct fb_info *info) struct fb_info *info)
...@@ -991,92 +988,74 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file, ...@@ -991,92 +988,74 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
case MATROXFB_SET_OUTPUT_MODE: case MATROXFB_SET_OUTPUT_MODE:
{ {
struct matroxioc_output_mode mom; struct matroxioc_output_mode mom;
struct matrox_altout *oproc;
int val; int val;
if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom))) if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
return -EFAULT; return -EFAULT;
if (mom.output >= sizeof(u_int32_t)) if (mom.output >= MATROXFB_MAX_OUTPUTS)
return -EINVAL; return -ENXIO;
switch (mom.output) { down_read(&ACCESS_FBINFO(altout.lock));
case MATROXFB_OUTPUT_PRIMARY: oproc = ACCESS_FBINFO(outputs[mom.output]).output;
if (mom.mode != MATROXFB_OUTPUT_MODE_MONITOR) if (!oproc) {
return -EINVAL; val = -ENXIO;
/* mode did not change... */ } else if (!oproc->verifymode) {
return 0; if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
case MATROXFB_OUTPUT_SECONDARY: val = 0;
} else {
val = -EINVAL; val = -EINVAL;
down_read(&ACCESS_FBINFO(altout.lock)); }
if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device)) { } else {
if (ACCESS_FBINFO(altout.output)->verifymode) { val = oproc->verifymode(ACCESS_FBINFO(outputs[mom.output]).data, mom.mode);
val = ACCESS_FBINFO(altout.output)->verifymode(ACCESS_FBINFO(altout.device), mom.mode); }
} else { if (!val) {
if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) { if (ACCESS_FBINFO(outputs[mom.output]).mode != mom.mode) {
val = 0; ACCESS_FBINFO(outputs[mom.output]).mode = mom.mode;
} val = 1;
} }
} }
up_read(&ACCESS_FBINFO(altout.lock)); up_read(&ACCESS_FBINFO(altout.lock));
if (val != 0) if (val != 1)
return val; return val;
if (ACCESS_FBINFO(altout.mode) == mom.mode) switch (ACCESS_FBINFO(outputs[mom.output]).src) {
return 0; case MATROXFB_SRC_CRTC1:
ACCESS_FBINFO(altout.mode) = mom.mode; matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info);
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) break;
matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info); case MATROXFB_SRC_CRTC2:
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { {
struct matroxfb_dh_fb_info* crtc2; struct matroxfb_dh_fb_info* crtc2;
down_read(&ACCESS_FBINFO(crtc2.lock)); down_read(&ACCESS_FBINFO(crtc2.lock));
crtc2 = (struct matroxfb_dh_fb_info*)(ACCESS_FBINFO(crtc2.info)); crtc2 = (struct matroxfb_dh_fb_info*)ACCESS_FBINFO(crtc2.info);
if (crtc2) if (crtc2)
crtc2->fbcon.switch_con(crtc2->currcon, &crtc2->fbcon); crtc2->fbcon.switch_con(crtc2->fbcon.currcon, &crtc2->fbcon);
up_read(&ACCESS_FBINFO(crtc2.lock)); up_read(&ACCESS_FBINFO(crtc2.lock));
} }
return 0; break;
case MATROXFB_OUTPUT_DFP:
if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
return -ENXIO;
if (mom.mode!= MATROXFB_OUTPUT_MODE_MONITOR)
return -EINVAL;
/* mode did not change... */
return 0;
default:
return -EINVAL;
} }
return 0; return 0;
} }
case MATROXFB_GET_OUTPUT_MODE: case MATROXFB_GET_OUTPUT_MODE:
{ {
struct matroxioc_output_mode mom; struct matroxioc_output_mode mom;
struct matrox_altout *oproc;
int val; int val;
if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom))) if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
return -EFAULT; return -EFAULT;
if (mom.output >= sizeof(u_int32_t)) if (mom.output >= MATROXFB_MAX_OUTPUTS)
return -EINVAL; return -ENXIO;
switch (mom.output) { down_read(&ACCESS_FBINFO(altout.lock));
case MATROXFB_OUTPUT_PRIMARY: oproc = ACCESS_FBINFO(outputs[mom.output]).output;
mom.mode = MATROXFB_OUTPUT_MODE_MONITOR; if (!oproc) {
break; val = -ENXIO;
case MATROXFB_OUTPUT_SECONDARY: } else {
val = -EINVAL; mom.mode = ACCESS_FBINFO(outputs[mom.output]).mode;
down_read(&ACCESS_FBINFO(altout.lock)); val = 0;
if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device)) {
mom.mode = ACCESS_FBINFO(altout.mode);
val = 0;
}
up_read(&ACCESS_FBINFO(altout.lock));
if (val)
return val;
break;
case MATROXFB_OUTPUT_DFP:
if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
return -ENXIO;
mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
break;
default:
return -EINVAL;
} }
up_read(&ACCESS_FBINFO(altout.lock));
if (val)
return val;
if (copy_to_user((struct matroxioc_output_mode*)arg, &mom, sizeof(mom))) if (copy_to_user((struct matroxioc_output_mode*)arg, &mom, sizeof(mom)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -1084,47 +1063,104 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file, ...@@ -1084,47 +1063,104 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
case MATROXFB_SET_OUTPUT_CONNECTION: case MATROXFB_SET_OUTPUT_CONNECTION:
{ {
u_int32_t tmp; u_int32_t tmp;
int i;
int changes;
if (copy_from_user(&tmp, (u_int32_t*)arg, sizeof(tmp))) if (copy_from_user(&tmp, (u_int32_t*)arg, sizeof(tmp)))
return -EFAULT; return -EFAULT;
if (tmp & ~ACCESS_FBINFO(output.all)) for (i = 0; i < 32; i++) {
return -EINVAL; if (tmp & (1 << i)) {
if (tmp & ACCESS_FBINFO(output.sh)) if (i >= MATROXFB_MAX_OUTPUTS)
return -EINVAL; return -ENXIO;
if (tmp & MATROXFB_OUTPUT_CONN_DFP) { if (!ACCESS_FBINFO(outputs[i]).output)
if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY) return -ENXIO;
return -EINVAL; switch (ACCESS_FBINFO(outputs[i]).src) {
if (ACCESS_FBINFO(output.sh)) case MATROXFB_SRC_NONE:
return -EINVAL; case MATROXFB_SRC_CRTC1:
break;
default:
return -EBUSY;
}
}
}
if (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;
}
}
}
} }
if (tmp == ACCESS_FBINFO(output.ph)) changes = 0;
for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
if (tmp & (1 << i)) {
if (ACCESS_FBINFO(outputs[i]).src != MATROXFB_SRC_CRTC1) {
changes = 1;
ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_CRTC1;
}
} else if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
changes = 1;
ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_NONE;
}
}
if (!changes)
return 0; return 0;
ACCESS_FBINFO(output.ph) = tmp;
matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info); matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info);
return 0; return 0;
} }
case MATROXFB_GET_OUTPUT_CONNECTION: case MATROXFB_GET_OUTPUT_CONNECTION:
{ {
if (put_user(ACCESS_FBINFO(output.ph), (u_int32_t*)arg)) u_int32_t conn = 0;
int i;
for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
conn |= 1 << i;
}
}
if (put_user(conn, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case MATROXFB_GET_AVAILABLE_OUTPUTS: case MATROXFB_GET_AVAILABLE_OUTPUTS:
{ {
u_int32_t tmp; u_int32_t conn = 0;
int i;
tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.sh);
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
tmp &= ~MATROXFB_OUTPUT_CONN_SECONDARY; if (ACCESS_FBINFO(outputs[i]).output) {
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) switch (ACCESS_FBINFO(outputs[i]).src) {
tmp &= ~MATROXFB_OUTPUT_CONN_DFP; case MATROXFB_SRC_NONE:
if (put_user(tmp, (u_int32_t*)arg)) case MATROXFB_SRC_CRTC1:
conn |= 1 << i;
break;
}
}
}
if (ACCESS_FBINFO(devflags.panellink)) {
if (conn & MATROXFB_OUTPUT_CONN_DFP)
conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
if (conn & MATROXFB_OUTPUT_CONN_SECONDARY)
conn &= ~MATROXFB_OUTPUT_CONN_DFP;
}
if (put_user(conn, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case MATROXFB_GET_ALL_OUTPUTS: case MATROXFB_GET_ALL_OUTPUTS:
{ {
if (put_user(ACCESS_FBINFO(output.all), (u_int32_t*)arg)) u_int32_t conn = 0;
int i;
for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
if (ACCESS_FBINFO(outputs[i]).output) {
conn |= 1 << i;
}
}
if (put_user(conn, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
...@@ -1600,17 +1636,14 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){ ...@@ -1600,17 +1636,14 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){
ACCESS_FBINFO(devflags.maven_capable) = b->flags & DEVF_MAVEN_CAPABLE; ACCESS_FBINFO(devflags.maven_capable) = b->flags & DEVF_MAVEN_CAPABLE;
ACCESS_FBINFO(devflags.dualhead) = (b->flags & DEVF_DUALHEAD) != 0; ACCESS_FBINFO(devflags.dualhead) = (b->flags & DEVF_DUALHEAD) != 0;
if (b->flags & DEVF_PANELLINK_CAPABLE) { if (b->flags & DEVF_PANELLINK_CAPABLE) {
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_DFP; ACCESS_FBINFO(outputs[2]).data = MINFO;
ACCESS_FBINFO(outputs[2]).output = &panellink_output;
if (dfp) if (dfp)
ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_DFP; ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
} else if (b->flags & DEVF_DUALHEAD) { else
#ifdef CONFIG_FB_MATROX_G450 ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY; ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_SECONDARY; ACCESS_FBINFO(devflags.panellink) = 1;
#else
printk(KERN_INFO "Only digital output of G550 is now working (in analog mode). Enable G450 support in\n");
printk(KERN_INFO "kernel configuration if you have analog monitor connected to G550 analog output.\n");
#endif
} }
ACCESS_FBINFO(devflags.dfp_type) = dfp_type; ACCESS_FBINFO(devflags.dfp_type) = dfp_type;
ACCESS_FBINFO(devflags.g450dac) = b->flags & DEVF_G450DAC; ACCESS_FBINFO(devflags.g450dac) = b->flags & DEVF_G450DAC;
...@@ -2061,10 +2094,6 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm ...@@ -2061,10 +2094,6 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
init_rwsem(&ACCESS_FBINFO(crtc2.lock)); init_rwsem(&ACCESS_FBINFO(crtc2.lock));
init_rwsem(&ACCESS_FBINFO(altout.lock)); init_rwsem(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(output.all) = MATROXFB_OUTPUT_CONN_PRIMARY;
ACCESS_FBINFO(output.ph) = MATROXFB_OUTPUT_CONN_PRIMARY;
ACCESS_FBINFO(output.sh) = 0;
err = initMatrox2(PMINFO d, b); err = initMatrox2(PMINFO d, b);
if (!err) { if (!err) {
#ifndef CONFIG_FB_MATROX_MULTIHEAD #ifndef CONFIG_FB_MATROX_MULTIHEAD
...@@ -2478,8 +2507,8 @@ int __init matroxfb_init(void) ...@@ -2478,8 +2507,8 @@ int __init matroxfb_init(void)
/* *************************** init module code **************************** */ /* *************************** init module code **************************** */
MODULE_AUTHOR("(c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450"); MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_PARM(mem, "i"); MODULE_PARM(mem, "i");
......
...@@ -396,12 +396,17 @@ struct matrox_accel_data { ...@@ -396,12 +396,17 @@ struct matrox_accel_data {
}; };
struct matrox_altout { struct matrox_altout {
const char *name;
int (*compute)(void* altout_dev, struct my_timming* input); int (*compute)(void* altout_dev, struct my_timming* input);
int (*program)(void* altout_dev); int (*program)(void* altout_dev);
int (*start)(void* altout_dev); int (*start)(void* altout_dev);
int (*verifymode)(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 }; enum mga_chip { MGA_2064, MGA_2164, MGA_1064, MGA_1164, MGA_G100, MGA_G200, MGA_G400, MGA_G450, MGA_G550 };
struct matrox_bios { struct matrox_bios {
...@@ -435,22 +440,20 @@ struct matrox_fb_info { ...@@ -435,22 +440,20 @@ struct matrox_fb_info {
struct pci_dev* pcidev; struct pci_dev* pcidev;
struct {
u_int32_t all;
u_int32_t ph;
u_int32_t sh;
} output;
struct matrox_altout* primout;
struct { struct {
struct fb_info* info; struct fb_info* info;
struct rw_semaphore lock; struct rw_semaphore lock;
} crtc2; } crtc2;
struct { struct {
struct rw_semaphore lock;
} altout;
#define MATROXFB_MAX_OUTPUTS 3
struct {
unsigned int src;
struct matrox_altout* output; struct matrox_altout* output;
void* device; void* data;
struct rw_semaphore lock;
unsigned int mode; unsigned int mode;
} altout; } outputs[MATROXFB_MAX_OUTPUTS];
#define MATROXFB_MAX_FB_DRIVERS 5 #define MATROXFB_MAX_FB_DRIVERS 5
struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]); struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]);
...@@ -539,6 +542,7 @@ struct matrox_fb_info { ...@@ -539,6 +542,7 @@ struct matrox_fb_info {
int memtype; int memtype;
int g450dac; int g450dac;
int dfp_type; int dfp_type;
int panellink; /* G400 DFP possible (not G450/G550) */
int dualhead; int dualhead;
unsigned int fbResource; unsigned int fbResource;
} devflags; } devflags;
......
...@@ -118,25 +118,22 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, ...@@ -118,25 +118,22 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
break; break;
} }
if (ACCESS_FBINFO(output.sh)) { tmp |= 0x00000001; /* enable CRTC2 */
tmp |= 0x00000001; /* enable CRTC2 */ if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
if (ACCESS_FBINFO(devflags.g450dac)) {
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { tmp |= 0x00000006; /* source from secondary pixel PLL */
if (ACCESS_FBINFO(devflags.g450dac)) { /* no vidrst */
tmp |= 0x00000006; /* source from secondary pixel PLL */ } else {
/* no vidrst */ tmp |= 0x00000002; /* source from VDOCLK */
} else { tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
tmp |= 0x00000002; /* source from VDOCLK */ /* MGA TVO is our clock source */
tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
/* MGA TVO is our clock source */
}
} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
tmp |= 0x00000004; /* source from pixclock */
/* PIXPLL is our clock source */
} }
} else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) tmp |= 0x00000004; /* source from pixclock */
tmp |= 0x00100000; /* connect CRTC2 to DAC */ /* PIXPLL is our clock source */
}
if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
tmp |= 0x00100000; /* connect CRTC2 to DAC */
} }
if (mt->interlaced) { if (mt->interlaced) {
tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */ tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */
...@@ -172,6 +169,12 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, ...@@ -172,6 +169,12 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
mga_outl(0x3C4C, 0); /* data control */ mga_outl(0x3C4C, 0); /* data control */
} }
static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
MINFO_FROM(m2info->primary_dev);
mga_outl(0x3C10, 0x00000004); /* disable CRTC2, CRTC1->DAC1, PLL as clock source */
}
static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info, static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info,
struct display* p) { struct display* p) {
/* no acceleration for secondary head... */ /* no acceleration for secondary head... */
...@@ -411,6 +414,8 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, ...@@ -411,6 +414,8 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
if (con == m2info->fbcon.currcon) { if (con == m2info->fbcon.currcon) {
struct my_timming mt; struct my_timming mt;
unsigned int pos; unsigned int pos;
int out;
int cnt;
matroxfb_var2my(var, &mt); matroxfb_var2my(var, &mt);
/* CRTC2 delay */ /* CRTC2 delay */
...@@ -418,39 +423,38 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, ...@@ -418,39 +423,38 @@ static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3; pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3;
pos += m2info->video.offbase; pos += m2info->video.offbase;
DAC1064_global_init(PMINFO2); cnt = 0;
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) { down_read(&ACCESS_FBINFO(altout).lock);
if (ACCESS_FBINFO(primout) && ACCESS_FBINFO(primout)->compute) for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
ACCESS_FBINFO(primout)->compute(MINFO, &mt); if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
cnt++;
if (ACCESS_FBINFO(outputs[out]).output->compute) {
ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
}
}
} }
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { up_read(&ACCESS_FBINFO(altout).lock);
down_read(&ACCESS_FBINFO(altout.lock)); if (cnt) {
if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.output)->compute) matroxfb_dh_restore(m2info, &mt, p, mode, pos);
ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt); } else {
up_read(&ACCESS_FBINFO(altout.lock)); matroxfb_dh_disable(m2info);
} }
matroxfb_dh_restore(m2info, &mt, p, mode, pos); DAC1064_global_init(PMINFO2);
DAC1064_global_restore(PMINFO2); DAC1064_global_restore(PMINFO2);
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) { down_read(&ACCESS_FBINFO(altout).lock);
if (ACCESS_FBINFO(primout) && ACCESS_FBINFO(primout)->program) for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
ACCESS_FBINFO(primout)->program(MINFO); if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
} ACCESS_FBINFO(outputs[out]).output->program) {
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
down_read(&ACCESS_FBINFO(altout.lock)); }
if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.output)->program)
ACCESS_FBINFO(altout.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)
ACCESS_FBINFO(primout)->start(MINFO);
} }
if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
down_read(&ACCESS_FBINFO(altout.lock)); if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.output)->start) ACCESS_FBINFO(outputs[out]).output->start) {
ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device)); ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
up_read(&ACCESS_FBINFO(altout.lock)); }
} }
up_read(&ACCESS_FBINFO(altout).lock);
matroxfb_dh_cfbX_init(m2info, p); matroxfb_dh_cfbX_init(m2info, p);
my_install_cmap(m2info); my_install_cmap(m2info);
} }
...@@ -563,38 +567,84 @@ static int matroxfb_dh_ioctl(struct inode* inode, ...@@ -563,38 +567,84 @@ static int matroxfb_dh_ioctl(struct inode* inode,
case MATROXFB_SET_OUTPUT_CONNECTION: case MATROXFB_SET_OUTPUT_CONNECTION:
{ {
u_int32_t tmp; u_int32_t tmp;
int out;
int changes;
if (get_user(tmp, (u_int32_t*)arg)) if (get_user(tmp, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
if (tmp & ~ACCESS_FBINFO(output.all)) for (out = 0; out < 32; out++) {
return -EINVAL; if (tmp & (1 << out)) {
if (tmp & ACCESS_FBINFO(output.ph)) if (out >= MATROXFB_MAX_OUTPUTS)
return -EINVAL; return -ENXIO;
if (tmp & MATROXFB_OUTPUT_CONN_DFP) if (!ACCESS_FBINFO(outputs[out]).output)
return -EINVAL; return -ENXIO;
if ((ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) && tmp) switch (ACCESS_FBINFO(outputs[out]).src) {
return -EINVAL; case MATROXFB_SRC_NONE:
if (tmp == ACCESS_FBINFO(output.sh)) case MATROXFB_SRC_CRTC2:
break;
default:
return -EBUSY;
}
}
}
if (ACCESS_FBINFO(devflags.panellink)) {
if (tmp & MATROXFB_OUTPUT_CONN_DFP)
return -EINVAL;
if ((ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) && tmp)
return -EBUSY;
}
changes = 0;
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (tmp & (1 << out)) {
if (ACCESS_FBINFO(outputs[out]).src != MATROXFB_SRC_CRTC2) {
changes = 1;
ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_CRTC2;
}
} else if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
changes = 1;
ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_NONE;
}
}
if (!changes)
return 0; return 0;
ACCESS_FBINFO(output.sh) = tmp;
matroxfb_dh_switch(m2info->fbcon.currcon, info); matroxfb_dh_switch(m2info->fbcon.currcon, info);
return 0; return 0;
} }
case MATROXFB_GET_OUTPUT_CONNECTION: case MATROXFB_GET_OUTPUT_CONNECTION:
{ {
if (put_user(ACCESS_FBINFO(output.sh), (u_int32_t*)arg)) u_int32_t conn = 0;
int out;
for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
conn |= 1 << out;
}
}
if (put_user(conn, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case MATROXFB_GET_AVAILABLE_OUTPUTS: case MATROXFB_GET_AVAILABLE_OUTPUTS:
{ {
u_int32_t tmp; u_int32_t tmp = 0;
int out;
/* we do not support DFP from CRTC2 */
tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph) & ~MATROXFB_OUTPUT_CONN_DFP; for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
/* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */ if (ACCESS_FBINFO(outputs[out]).output) {
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) switch (ACCESS_FBINFO(outputs[out]).src) {
tmp = 0; case MATROXFB_SRC_NONE:
case MATROXFB_SRC_CRTC2:
tmp |= 1 << out;
break;
}
}
}
if (ACCESS_FBINFO(devflags.panellink)) {
tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) {
tmp = 0;
}
}
if (put_user(tmp, (u_int32_t*)arg)) if (put_user(tmp, (u_int32_t*)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -730,11 +780,10 @@ static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) { ...@@ -730,11 +780,10 @@ static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) {
/* /*
* If we have unused output, connect CRTC2 to it... * If we have unused output, connect CRTC2 to it...
*/ */
if ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) && if (ACCESS_FBINFO(outputs[1]).output &&
!(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) && ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_NONE &&
!(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) { ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_NONE) {
ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY; ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC2;
ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP;
} }
matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon); matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon);
...@@ -839,7 +888,7 @@ static void matroxfb_crtc2_exit(void) { ...@@ -839,7 +888,7 @@ static void matroxfb_crtc2_exit(void) {
matroxfb_unregister_driver(&crtc2); matroxfb_unregister_driver(&crtc2);
} }
MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
MODULE_DESCRIPTION("Matrox G400 CRTC2 driver"); MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(matroxfb_crtc2_init); module_init(matroxfb_crtc2_init);
......
...@@ -34,30 +34,31 @@ static int matroxfb_g450_program(void* md) { ...@@ -34,30 +34,31 @@ static int matroxfb_g450_program(void* md) {
} }
static struct matrox_altout matroxfb_g450_altout = { static struct matrox_altout matroxfb_g450_altout = {
.name = "Secondary output",
.compute = matroxfb_g450_compute, .compute = matroxfb_g450_compute,
.program = matroxfb_g450_program, .program = matroxfb_g450_program,
}; };
void matroxfb_g450_connect(WPMINFO2) { void matroxfb_g450_connect(WPMINFO2) {
/* hardware is not G450... */ if (ACCESS_FBINFO(devflags.g450dac)) {
if (!ACCESS_FBINFO(devflags.g450dac)) down_write(&ACCESS_FBINFO(altout.lock));
return; ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC1;
down_write(&ACCESS_FBINFO(altout.lock)); ACCESS_FBINFO(outputs[1]).data = MINFO;
ACCESS_FBINFO(altout.device) = MINFO; ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout;
ACCESS_FBINFO(altout.output) = &matroxfb_g450_altout; ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
up_write(&ACCESS_FBINFO(altout.lock)); up_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY; }
matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), (struct fb_info*)MINFO);
} }
void matroxfb_g450_shutdown(WPMINFO2) { void matroxfb_g450_shutdown(WPMINFO2) {
ACCESS_FBINFO(output.all) &= ~MATROXFB_OUTPUT_CONN_SECONDARY; if (ACCESS_FBINFO(devflags.g450dac)) {
ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_SECONDARY; down_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_SECONDARY; ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
down_write(&ACCESS_FBINFO(altout.lock)); ACCESS_FBINFO(outputs[1]).output = NULL;
ACCESS_FBINFO(altout.device) = NULL; ACCESS_FBINFO(outputs[1]).data = NULL;
ACCESS_FBINFO(altout.output) = NULL; ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
up_write(&ACCESS_FBINFO(altout.lock)); up_write(&ACCESS_FBINFO(altout.lock));
}
} }
EXPORT_SYMBOL(matroxfb_g450_connect); EXPORT_SYMBOL(matroxfb_g450_connect);
......
...@@ -327,7 +327,7 @@ static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* dat ...@@ -327,7 +327,7 @@ static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* dat
}, MODE_NTSC, 525, 60 }; }, MODE_NTSC, 525, 60 };
MINFO_FROM(md->primary_head); MINFO_FROM(md->primary_head);
if (ACCESS_FBINFO(altout.mode) == MODE_PAL) if (ACCESS_FBINFO(outputs[1]).mode == MODE_PAL)
*data = palregs; *data = palregs;
else else
*data = ntscregs; *data = ntscregs;
...@@ -585,7 +585,7 @@ static inline int maven_compute_timming(struct maven_data* md, ...@@ -585,7 +585,7 @@ static inline int maven_compute_timming(struct maven_data* md,
unsigned int a, bv, c; unsigned int a, bv, c;
MINFO_FROM(md->primary_head); MINFO_FROM(md->primary_head);
m->mode = ACCESS_FBINFO(altout.mode); m->mode = ACCESS_FBINFO(outputs[1]).mode;
if (MODE_TV(m->mode)) { if (MODE_TV(m->mode)) {
unsigned int lmargin; unsigned int lmargin;
unsigned int umargin; unsigned int umargin;
...@@ -893,6 +893,7 @@ static int maven_out_verify_mode(void* md, u_int32_t arg) { ...@@ -893,6 +893,7 @@ static int maven_out_verify_mode(void* md, u_int32_t arg) {
} }
static struct matrox_altout maven_altout = { static struct matrox_altout maven_altout = {
.name = "Secondary output",
.compute = maven_out_compute, .compute = maven_out_compute,
.program = maven_out_program, .program = maven_out_program,
.start = maven_out_start, .start = maven_out_start,
...@@ -904,14 +905,14 @@ static int maven_init_client(struct i2c_client* clnt) { ...@@ -904,14 +905,14 @@ static int maven_init_client(struct i2c_client* clnt) {
struct maven_data* md = clnt->data; struct maven_data* md = clnt->data;
MINFO_FROM(((struct i2c_bit_adapter*)a)->minfo); MINFO_FROM(((struct i2c_bit_adapter*)a)->minfo);
ACCESS_FBINFO(altout.mode) = MODE_MONITOR;
md->primary_head = MINFO; md->primary_head = MINFO;
md->client = clnt; md->client = clnt;
down_write(&ACCESS_FBINFO(altout.lock)); down_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(altout.device) = md; ACCESS_FBINFO(outputs[1]).output = &maven_altout;
ACCESS_FBINFO(altout.output) = &maven_altout; ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
ACCESS_FBINFO(outputs[1]).data = md;
ACCESS_FBINFO(outputs[1]).mode = MODE_MONITOR;
up_write(&ACCESS_FBINFO(altout.lock)); up_write(&ACCESS_FBINFO(altout.lock));
ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
if (maven_get_reg(clnt, 0xB2) < 0x14) { if (maven_get_reg(clnt, 0xB2) < 0x14) {
md->version = MGATVO_B; md->version = MGATVO_B;
} else { } else {
...@@ -924,13 +925,14 @@ static int maven_shutdown_client(struct i2c_client* clnt) { ...@@ -924,13 +925,14 @@ static int maven_shutdown_client(struct i2c_client* clnt) {
struct maven_data* md = clnt->data; struct maven_data* md = clnt->data;
if (md->primary_head) { if (md->primary_head) {
md->primary_head->output.all &= ~MATROXFB_OUTPUT_CONN_SECONDARY; MINFO_FROM(md->primary_head);
md->primary_head->output.ph &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
md->primary_head->output.sh &= ~MATROXFB_OUTPUT_CONN_SECONDARY; down_write(&ACCESS_FBINFO(altout.lock));
down_write(&md->primary_head->altout.lock); ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
md->primary_head->altout.device = NULL; ACCESS_FBINFO(outputs[1]).output = NULL;
md->primary_head->altout.output = NULL; ACCESS_FBINFO(outputs[1]).data = NULL;
up_write(&md->primary_head->altout.lock); ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
up_write(&ACCESS_FBINFO(altout.lock));
md->primary_head = NULL; md->primary_head = NULL;
} }
return 0; return 0;
......
...@@ -360,7 +360,8 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p) { ...@@ -360,7 +360,8 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p) {
((hd & 0x100) >> 7) | /* blanking */ ((hd & 0x100) >> 7) | /* blanking */
((hs & 0x100) >> 6) | /* sync start */ ((hs & 0x100) >> 6) | /* sync start */
(hbe & 0x040); /* end hor. blanking */ (hbe & 0x040); /* end hor. blanking */
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) /* FIXME: Enable vidrst only on G400, and only if TV-out is used */
if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1)
hw->CRTCEXT[1] |= 0x88; /* enable horizontal and vertical vidrst */ hw->CRTCEXT[1] |= 0x88; /* enable horizontal and vertical vidrst */
hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) | hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) |
((vd & 0x400) >> 8) | /* disp end */ ((vd & 0x400) >> 8) | /* disp end */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment