/* (c) 1998-2001 Petr Vandrovec This code originally comes from matroxfb. Relicensed under the LGPL with the authors permission. Adapted for CRTC2 ITU-R 656 mode by Ville Syrjala This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "matrox.h" #include "regs.h" #include "mmio.h" #include "matrox_maven.h" #define SYS_CLASS_I2C_DEV "/sys/class/i2c-dev" static void maven_write_byte( MatroxMavenData *mav, MatroxDriverData *mdrv, u8 reg, u8 val ) { MatroxDeviceData *mdev = mdrv->device_data; if (mdev->g450_matrox) { volatile u8 *mmio = mdrv->mmio_base; mga_out_dac( mmio, 0x87, reg ); mga_out_dac( mmio, 0x88, val ); } else { union i2c_smbus_data data; struct i2c_smbus_ioctl_data args; data.byte = val; args.read_write = I2C_SMBUS_WRITE; args.command = reg; args.size = I2C_SMBUS_BYTE_DATA; args.data = &data; ioctl( mdrv->maven_fd, I2C_SMBUS, &args ); } } static void maven_write_word( MatroxMavenData *mav, MatroxDriverData *mdrv, u8 reg, u16 val ) { MatroxDeviceData *mdev = mdrv->device_data; if (mdev->g450_matrox) { volatile u8 *mmio = mdrv->mmio_base; mga_out_dac( mmio, 0x87, reg ); mga_out_dac( mmio, 0x88, val ); mga_out_dac( mmio, 0x87, reg + 1 ); mga_out_dac( mmio, 0x88, val >> 8 ); } else { union i2c_smbus_data data; struct i2c_smbus_ioctl_data args; data.word = val; args.read_write = I2C_SMBUS_WRITE; args.command = reg; args.size = I2C_SMBUS_WORD_DATA; args.data = &data; ioctl( mdrv->maven_fd, I2C_SMBUS, &args ); } } #if 0 /* i2c_smbus_read_byte_data() doesn't work with maven. */ static int i2c_read_byte( int fd, u8 addr, u8 reg ) { int ret; u8 val; struct i2c_msg msgs[] = { { addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® }, { addr, I2C_M_RD | I2C_M_NOSTART, sizeof(val), &val } }; struct i2c_rdwr_ioctl_data data = { msgs, 2 }; ret = ioctl( fd, I2C_RDWR, &data ); if (ret < 0) return ret; return val; } #endif void maven_disable( MatroxMavenData *mav, MatroxDriverData *mdrv ) { MatroxDeviceData *mdev = mdrv->device_data; maven_write_byte( mav, mdrv, 0x3E, 0x01 ); if (mdev->g450_matrox) { maven_write_byte( mav, mdrv, 0x80, 0x00 ); return; } maven_write_byte( mav, mdrv, 0x82, 0x80 ); maven_write_byte( mav, mdrv, 0x8C, 0x00 ); maven_write_byte( mav, mdrv, 0x94, 0xA2 ); maven_write_word( mav, mdrv, 0x8E, 0x1EFF ); maven_write_byte( mav, mdrv, 0xC6, 0x01 ); } void maven_enable( MatroxMavenData *mav, MatroxDriverData *mdrv ) { MatroxDeviceData *mdev = mdrv->device_data; bool ntsc = dfb_config->matrox_tv_std != DSETV_PAL; if (mdev->g450_matrox) { if (dfb_config->matrox_cable == 1) /* SCART RGB */ maven_write_byte( mav, mdrv, 0x80, ntsc ? 0x43 : 0x41 ); else /* Composite / S-Video */ maven_write_byte( mav, mdrv, 0x80, ntsc ? 0x03 : 0x01 ); } else maven_write_byte( mav, mdrv, 0x82, 0x20 ); maven_write_byte( mav, mdrv, 0x3E, 0x00 ); } void maven_sync( MatroxMavenData *mav, MatroxDriverData *mdrv ) { MatroxDeviceData *mdev = mdrv->device_data; if (mdev->g450_matrox) return; maven_write_byte( mav, mdrv, 0xD4, 0x01 ); maven_write_byte( mav, mdrv, 0xD4, 0x00 ); } #define LR(x) maven_write_byte( mav, mdrv, (x), mav->regs[(x)] ) #define LRP(x) maven_write_word( mav, mdrv, (x), mav->regs[(x)] | (mav->regs[(x)+1] << 8) ) void maven_set_regs( MatroxMavenData *mav, MatroxDriverData *mdrv, CoreLayerRegionConfig *config, DFBColorAdjustment *adj ) { MatroxDeviceData *mdev = mdrv->device_data; bool ntsc = dfb_config->matrox_tv_std != DSETV_PAL; LR(0x00); LR(0x01); LR(0x02); LR(0x03); LR(0x04); LR(0x2C); LR(0x08); LR(0x0A); LR(0x09); LR(0x29); LRP(0x31); LRP(0x17); LR(0x0B); LR(0x0C); LR(0x35); LRP(0x10); LRP(0x0E); LRP(0x1E); LR(0x20); LR(0x22); LR(0x25); LR(0x34); LR(0x33); LR(0x19); LR(0x12); LR(0x3B); LR(0x13); LR(0x39); LR(0x1D); LR(0x3A); LR(0x24); LR(0x14); LR(0x15); LR(0x16); LRP(0x2D); LRP(0x2F); LR(0x1A); LR(0x1B); LR(0x1C); LR(0x23); LR(0x26); LR(0x28); LR(0x27); LR(0x21); LRP(0x2A); LR(0x35); LRP(0x3C); LR(0x37); LR(0x38); if (mdev->g450_matrox) { maven_write_word( mav, mdrv, 0x82, ntsc ? 0x0014 : 0x0017 ); maven_write_word( mav, mdrv, 0x84, 0x0001 ); } else { maven_write_byte( mav, mdrv, 0xB3, 0x01 ); maven_write_byte( mav, mdrv, 0x82, 0xA0 ); maven_write_byte( mav, mdrv, 0xD3, 0x01 ); maven_write_byte( mav, mdrv, 0x8C, 0x10 ); maven_write_byte( mav, mdrv, 0x94, 0xA2 ); maven_write_byte( mav, mdrv, 0x8D, 0x03 ); maven_write_byte( mav, mdrv, 0xB9, 0x78 ); maven_write_byte( mav, mdrv, 0xBF, 0x02 ); /* * Deflicker: 0x00, 0xB1, 0xA2 * Doesn't work due to: * - ITU-R BT.656 mode? * - scaler is not used? * - something else? */ maven_write_byte( mav, mdrv, 0x93, 0x00 ); } maven_set_saturation( mav, mdrv, adj->saturation >> 8 ); maven_set_hue( mav, mdrv, adj->hue >> 8 ); maven_set_bwlevel( mav, mdrv, adj->brightness >> 8, adj->contrast >> 8 ); if (!mdev->g450_matrox) { LR(0x83); LR(0x84); LR(0x85); LR(0x86); LR(0x87); LR(0x88); LR(0x89); LR(0x8A); LR(0x8B); switch (dfb_config->matrox_cable) { case 1: /* SCART RGB */ maven_write_byte( mav, mdrv, 0xB0, 0x85 ); break; case 2: /* SCART Composite */ maven_write_byte( mav, mdrv, 0xB0, 0x81 ); break; default: /* Composite / S-Video */ maven_write_byte( mav, mdrv, 0xB0, 0x80 ); break; } } } void maven_set_hue( MatroxMavenData *mav, MatroxDriverData *mdrv, u8 hue ) { maven_write_byte( mav, mdrv, 0x25, hue ); } void maven_set_saturation( MatroxMavenData *mav, MatroxDriverData *mdrv, u8 saturation ) { maven_write_byte( mav, mdrv, 0x20, saturation ); maven_write_byte( mav, mdrv, 0x22, saturation ); } void maven_set_bwlevel( MatroxMavenData *mav, MatroxDriverData *mdrv, u8 brightness, u8 contrast ) { MatroxDeviceData *mdev = mdrv->device_data; int b, c, bl, wl, wlmax, blmin, range; bool ntsc = dfb_config->matrox_tv_std == DSETV_NTSC; if (mdev->g450_matrox) { wlmax = ntsc ? 936 : 938; blmin = ntsc ? 267 : 281; } else { wlmax = 786; blmin = ntsc ? 242 : 255; } range = wlmax - blmin - 128; b = brightness * range / 255 + blmin; c = contrast * range / 2 / 255 + 64; bl = MAX( b - c, blmin ); wl = MIN( b + c, wlmax ); blmin = ((blmin << 8) & 0x0300) | ((blmin >> 2) & 0x00FF); bl = ((bl << 8) & 0x0300) | ((bl >> 2) & 0x00FF); wl = ((wl << 8) & 0x0300) | ((wl >> 2) & 0x00FF); maven_write_word( mav, mdrv, 0x10, blmin ); maven_write_word( mav, mdrv, 0x0E, bl ); maven_write_word( mav, mdrv, 0x1E, wl ); } DFBResult maven_open( MatroxMavenData *mav, MatroxDriverData *mdrv ) { MatroxDeviceData *mdev = mdrv->device_data; if (mdev->g450_matrox) return DFB_OK; if (mdrv->maven_fd != -1) D_BUG( "DirectFB/Matrox/Maven: Device already open!\n" ); if ((mdrv->maven_fd = open( mav->dev, O_RDWR )) < 0) { D_PERROR( "DirectFB/Matrox/Maven: Error opening `%s'!\n", mav->dev ); mdrv->maven_fd = -1; return errno2result( errno ); } if (ioctl( mdrv->maven_fd, I2C_SLAVE, mav->address ) < 0) { D_PERROR( "DirectFB/Matrox/Maven: Error controlling `%s'!\n", mav->dev ); close( mdrv->maven_fd ); mdrv->maven_fd = -1; return errno2result( errno ); } return DFB_OK; } void maven_close( MatroxMavenData *mav, MatroxDriverData *mdrv ) { MatroxDeviceData *mdev = mdrv->device_data; if (mdev->g450_matrox) return; if (mdrv->maven_fd == -1) D_BUG( "DirectFB/Matrox/Maven: Device not open!\n" ); close( mdrv->maven_fd ); mdrv->maven_fd = -1; } DFBResult maven_init( MatroxMavenData *mav, MatroxDriverData *mdrv ) { MatroxDeviceData *mdev = mdrv->device_data; char line[512]; int fd; FILE *file; bool found = false; DIR *dir; /* Locate G400 maven /dev/i2c file */ /* Try sysfs */ if (!mdev->g450_matrox && (dir = opendir( SYS_CLASS_I2C_DEV )) != NULL) { char path[PATH_MAX]; struct dirent *ent; while ((ent = readdir( dir )) != NULL) { FILE *fp; if (!strcmp( ent->d_name, "." )) continue; if (!strcmp( ent->d_name, ".." )) continue; snprintf( path, sizeof(path), "%s/%s/name", SYS_CLASS_I2C_DEV, ent->d_name ); fp = fopen( path, "r" ); if (!fp) { D_PERROR( "DirectFB/Matrox/Maven: Error opening `%s'!\n", path ); continue; } memset( line, 0, 6 ); fread( line, 1, 5, fp ); if (ferror( fp )) { D_PERROR( "DirectFB/Matrox/Maven: Error reading `%s'!\n", path ); fclose( fp ); continue; } fclose( fp ); if (strcmp( line, "MAVEN" )) continue; snprintf( mav->dev, sizeof(mav->dev), "/dev/%s", ent->d_name ); found = true; break; } if (!ent && errno) D_PERROR( "DirectFB/Matrox/Maven: Error reading `%s'!\n", SYS_CLASS_I2C_DEV ); closedir( dir ); } /* Try /proc/bus/i2c */ if (!mdev->g450_matrox && !found) { file = fopen( "/proc/bus/i2c", "r" ); if (!file) { D_PERROR( "DirectFB/Matrox/Maven: " "Error opening `/proc/bus/i2c'!\n" ); return errno2result( errno ); } while (fgets( line, 512, file )) { if (strstr( line, "MAVEN" )) { char *p = line; while (!isspace( *p )) p++; *p = '\0'; direct_snputs( mav->dev, "/dev/", 6 ); strncat( mav->dev, line, 250 ); found = true; break; } } fclose( file ); } if (!mdev->g450_matrox) { if (!found) { D_ERROR( "DirectFB/Matrox/Maven: " "Can't find MAVEN i2c device file!\n" ); return DFB_UNSUPPORTED; } /* Try to use it */ if ((fd = open( mav->dev, O_RDWR )) < 0) { D_PERROR( "DirectFB/Matrox/Maven: Error opening `%s'!\n", mav->dev ); return errno2result( errno ); } #if 0 /* FIXME: This fails for some people */ /* Check if maven is at address 0x1B (DH board) or 0x1A (DH add-on) */ if (i2c_read_byte( fd, 0x1B, 0xB2 ) < 0) { if (i2c_read_byte( fd, 0x1A, 0xB2 ) < 0) { D_ERROR( "DirectFB/Matrox/Maven: Error reading from maven chip!\n" ); close( fd ); return errno2result( errno ); } else mav->address = 0x1A; } else mav->address = 0x1B; #else mav->address = 0x1B; #endif close( fd ); } /* Maven registers */ { static const u8 ntscregs[2][0x40] = { /* G400 */ { 0x21, 0xF0, 0x7C, 0x1F, /* 00-03 */ 0x00, /* 04 */ 0x00, 0x00, 0x00, 0x7E, /* 08 */ 0x43, /* 09 */ 0x7E, /* 0A */ 0x3D, /* 0B */ 0x00, /* 0C */ 0x00, 0x46, 0x03, /* 0E-0F */ 0x3C, 0x02, /* 10-11 */ 0x17, /* 12 */ 0x21, /* 13 */ 0x1B, /* 14 */ 0x1B, /* 15 */ 0x24, /* 16 */ 0x83, 0x01, /* 17-18 */ 0x00, /* 19 */ 0x0F, /* 1A */ 0x0F, /* 1B */ 0x60, /* 1C */ 0x05, /* 1D */ 0xC4, 0x02, /* 1E-1F */ 0x8E, /* 20 */ 0x04, /* 21 */ 0x8E, /* 22 */ 0x01, /* 23 */ 0x02, /* 24 */ 0x00, /* 25 */ 0x0A, /* 26 */ 0x05, /* 27 */ 0x00, /* 28 */ 0x10, /* 29 */ 0xFF, 0x03, /* 2A-2B */ 0x18, /* 2C */ 0x0F, 0x78, /* 2D-2E */ 0x00, 0x00, /* 2F-30 */ 0xB4, 0x00, /* 31-32 */ 0x14, /* 33 */ 0x02, /* 34 */ 0x1C, /* 35 */ 0x00, 0xA3, /* 37 */ 0xC8, /* 38 */ 0x15, /* 39 */ 0x05, /* 3A */ 0x15, /* 3B */ 0x3C, 0x00, /* 3C-3D */ 0x00, /* 3E */ 0x00 }, /* G450 / G550 */ { 0x21, 0xF0, 0x7C, 0x1F, /* 00-03 */ 0x00, /* 04 */ 0x00, 0x00, 0x00, 0x7E, /* 08 */ 0x44, /* 09 */ 0x76, /* 0A */ 0x49, /* 0B */ 0x00, /* 0C */ 0x00, 0x4E, 0x03, /* 0E-0F */ 0x42, 0x03, /* 10-11 */ 0x17, /* 12 */ 0x21, /* 13 */ 0x1B, /* 14 */ 0x1B, /* 15 */ 0x24, /* 16 */ 0x83, 0x01, /* 17-18 */ 0x00, /* 19 */ 0x0F, /* 1A */ 0x0F, /* 1B */ 0x60, /* 1C */ 0x05, /* 1D */ 0xEA, 0x00, /* 1E-1F */ 0xAE, /* 20 */ 0x04, /* 21 */ 0xAE, /* 22 */ 0x01, /* 23 */ 0x02, /* 24 */ 0x00, /* 25 */ 0x0A, /* 26 */ 0x05, /* 27 */ 0x00, /* 28 */ 0x11, /* 29 */ 0xFF, 0x03, /* 2A-2B */ 0x20, /* 2C */ 0x0F, 0x78, /* 2D-2E */ 0x00, 0x00, /* 2F-30 */ 0xB4, 0x00, /* 31-32 */ 0x14, /* 33 */ 0x02, /* 34 */ 0x00, /* 35 */ 0x00, 0xBD, /* 37 */ 0xDA, /* 38 */ 0x15, /* 39 */ 0x05, /* 3A */ 0x15, /* 3B */ 0x42, 0x03, /* 3C-3D */ 0x00, /* 3E */ 0x00 } }; static const u8 palregs[2][0x40] = { /* G400 */ { 0x2A, 0x09, 0x8A, 0xCB, /* 00-03 */ 0x00, /* 04 */ 0x00, 0x00, 0x00, 0x7E, /* 08 */ 0x3C, /* 09 */ 0x82, /* 0A */ 0x2E, /* 0B */ 0x21, /* 0C */ 0x00, 0x3F, 0x03, /* 0E-0F */ 0x3F, 0x03, /* 10-11 */ 0x1A, /* 12 */ 0x2A, /* 13 */ 0x1C, /* 14 */ 0x3D, /* 15 */ 0x14, /* 16 */ 0x9C, 0x01, /* 17-18 */ 0x00, /* 19 */ 0xFE, /* 1A */ 0x7E, /* 1B */ 0x60, /* 1C */ 0x05, /* 1D */ 0xC4, 0x01, /* 1E-1F */ 0x95, /* 20 */ 0x07, /* 21 */ 0x95, /* 22 */ 0x00, /* 23 */ 0x00, /* 24 */ 0x00, /* 25 */ 0x08, /* 26 */ 0x04, /* 27 */ 0x00, /* 28 */ 0x1A, /* 29 */ 0x55, 0x01, /* 2A-2B */ 0x20, /* 2C */ 0x07, 0x7E, /* 2D-2E */ 0x02, 0x54, /* 2F-30 */ 0xB4, 0x00, /* 31-32 */ 0x14, /* 33 */ 0x49, /* 34 */ 0x1D, /* 35 */ 0x00, 0xA3, /* 37 */ 0xC8, /* 38 */ 0x22, /* 39 */ 0x02, /* 3A */ 0x22, /* 3B */ 0x3F, 0x03, /* 3C-3D */ 0x00, /* 3E */ 0x00, }, /* G450 / G550 */ { 0x2A, 0x09, 0x8A, 0xCB, /* 00-03 */ 0x00, /* 04 */ 0x00, 0x00, 0x00, 0x7E, /* 08 */ 0x3A, /* 09 */ 0x8A, /* 0A */ 0x38, /* 0B */ 0x28, /* 0C */ 0x00, 0x46, 0x01, /* 0E-0F */ 0x46, 0x01, /* 10-11 */ 0x1A, /* 12 */ 0x2A, /* 13 */ 0x1C, /* 14 */ 0x3D, /* 15 */ 0x14, /* 16 */ 0x9C, 0x01, /* 17-18 */ 0x00, /* 19 */ 0xFE, /* 1A */ 0x7E, /* 1B */ 0x60, /* 1C */ 0x05, /* 1D */ 0xEA, 0x00, /* 1E-1F */ 0xBB, /* 20 */ 0x07, /* 21 */ 0xBB, /* 22 */ 0x00, /* 23 */ 0x00, /* 24 */ 0x00, /* 25 */ 0x08, /* 26 */ 0x04, /* 27 */ 0x00, /* 28 */ 0x1A, /* 29 */ 0x55, 0x01, /* 2A-2B */ 0x18, /* 2C */ 0x07, 0x7E, /* 2D-2E */ 0x02, 0x54, /* 2F-30 */ 0xB4, 0x00, /* 31-32 */ 0x16, /* 33 */ 0x49, /* 34 */ 0x00, /* 35 */ 0x00, 0xB9, /* 37 */ 0xDD, /* 38 */ 0x22, /* 39 */ 0x02, /* 3A */ 0x22, /* 3B */ 0x46, 0x00, /* 3C-3D */ 0x00, /* 3E */ 0x00, } }; if (dfb_config->matrox_tv_std != DSETV_PAL) direct_memcpy( mav->regs, ntscregs[mdev->g450_matrox], 64 ); else direct_memcpy( mav->regs, palregs[mdev->g450_matrox], 64 ); if (dfb_config->matrox_tv_std == DSETV_PAL_60) { mav->regs[0x00] = palregs[mdev->g450_matrox][0x00]; mav->regs[0x01] = palregs[mdev->g450_matrox][0x01]; mav->regs[0x02] = palregs[mdev->g450_matrox][0x02]; mav->regs[0x03] = palregs[mdev->g450_matrox][0x03]; mav->regs[0x0B] = palregs[mdev->g450_matrox][0x0B]; mav->regs[0x0C] = palregs[mdev->g450_matrox][0x0C]; mav->regs[0x0E] = palregs[mdev->g450_matrox][0x0E]; mav->regs[0x0F] = palregs[mdev->g450_matrox][0x0F]; mav->regs[0x10] = palregs[mdev->g450_matrox][0x10]; mav->regs[0x11] = palregs[mdev->g450_matrox][0x11]; mav->regs[0x1E] = palregs[mdev->g450_matrox][0x1E]; mav->regs[0x1F] = palregs[mdev->g450_matrox][0x1F]; mav->regs[0x20] = palregs[mdev->g450_matrox][0x20]; mav->regs[0x22] = palregs[mdev->g450_matrox][0x22]; mav->regs[0x25] = palregs[mdev->g450_matrox][0x25]; mav->regs[0x34] = palregs[mdev->g450_matrox][0x34]; } if (!mdev->g450_matrox) { /* gamma */ mav->regs[0x83] = 0x00; mav->regs[0x84] = 0x00; mav->regs[0x85] = 0x00; mav->regs[0x86] = 0x1F; mav->regs[0x87] = 0x10; mav->regs[0x88] = 0x10; mav->regs[0x89] = 0x10; mav->regs[0x8A] = 0x64; mav->regs[0x8B] = 0xC8; } } return DFB_OK; }