diff options
Diffstat (limited to 'vidix/s3_vid.c')
-rw-r--r-- | vidix/s3_vid.c | 929 |
1 files changed, 929 insertions, 0 deletions
diff --git a/vidix/s3_vid.c b/vidix/s3_vid.c new file mode 100644 index 0000000000..849c28e0bb --- /dev/null +++ b/vidix/s3_vid.c @@ -0,0 +1,929 @@ +/* + * VIDIX driver for S3 chipsets. + * Copyright (C) 2004 Reza Jelveh + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MPlayer; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Thanks to Alex Deucher for Support + * + * Trio/Virge support by Michael Kostylev + * + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <unistd.h> +#include <math.h> + +#include "vidix.h" +#include "vidixlib.h" +#include "fourcc.h" +#include "dha.h" +#include "pci_ids.h" +#include "pci_names.h" +#include "config.h" + +#include "s3_regs.h" + +static void S3SetColorKeyOld (void); +static void S3SetColorKeyNew (void); +static void S3SetColorKey2000 (void); +static void (*S3SetColorKey) (void) = NULL; + +static void S3SetColorOld (void); +static void S3SetColorNew (void); +static void S3SetColor2000 (void); +static void (*S3SetColor) (void) = NULL; + +static void S3DisplayVideoOld (void); +static void S3DisplayVideoNew (void); +static void S3DisplayVideo2000 (void); +static void (*S3DisplayVideo) (void) = NULL; + +static void S3InitStreamsOld (void); +static void S3InitStreamsNew (void); +static void S3InitStreams2000 (void); +static void (*S3InitStreams) (void) = NULL; + +pciinfo_t pci_info; + +struct s3_chip +{ + int arch; + unsigned long fbsize; + void (*lock) (struct s3_chip *, int); +}; +typedef struct s3_chip s3_chip; + +struct s3_info +{ + vidix_video_eq_t eq; + unsigned int use_colorkey; + unsigned int colorkey; + unsigned int vidixcolorkey; + unsigned int depth; + unsigned int bpp; + unsigned int format; + unsigned int pitch; + unsigned int blendBase; + unsigned int displayWidth, displayHeight; + unsigned int src_w, src_h; + unsigned int drw_w, drw_h; + unsigned int wx, wy; + unsigned int screen_x; + unsigned int screen_y; + unsigned long frame_size; + struct s3_chip chip; + void *video_base; + void *control_base; + unsigned long picture_base; + unsigned long picture_offset; + unsigned int num_frames; + int bps; +}; +typedef struct s3_info s3_info; + +static s3_info *info; + +static vidix_capability_t s3_cap = { + "S3 BES", + "Reza Jelveh, Michael Kostylev", + TYPE_OUTPUT, + {0, 0, 0, 0}, + 4096, + 4096, + 4, + 4, + -1, + FLAG_UPSCALER | FLAG_DOWNSCALER, + VENDOR_S3_INC, + -1, + {0, 0, 0, 0} +}; + +struct s3_cards +{ + unsigned short chip_id; + unsigned short arch; +}; + +static struct s3_cards s3_card_ids[] = { + /* Trio64V */ + {DEVICE_S3_INC_86C764_765_TRIO32_64_64V, S3_TRIO64V}, + {DEVICE_S3_INC_86C767_TRIO_64UV, S3_TRIO64V}, + {DEVICE_S3_INC_86C755_TRIO_64V2_DX, S3_TRIO64V}, + {DEVICE_S3_INC_86C775_86C785_TRIO_64V2_DX, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY2, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY3, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY4, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY5, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY6, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY7, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY8, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY9, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY10, S3_TRIO64V}, + {DEVICE_S3_INC_TRIO_64V_FAMILY11, S3_TRIO64V}, + /* Virge */ + {DEVICE_S3_INC_86C325_VIRGE, S3_VIRGE}, + {DEVICE_S3_INC_86C988_VIRGE_VX, S3_VIRGE}, + {DEVICE_S3_INC_VIRGE_DX_OR_GX, S3_VIRGE}, + {DEVICE_S3_INC_VIRGE_GX2, S3_VIRGE}, + {DEVICE_S3_INC_VIRGE_M3, S3_VIRGE}, + {DEVICE_S3_INC_VIRGE_MX, S3_VIRGE}, + {DEVICE_S3_INC_VIRGE_MX2, S3_VIRGE}, + {DEVICE_S3_INC_VIRGE_MX_MV, S3_VIRGE}, + /* Savage3D */ + {DEVICE_S3_INC_86C794_SAVAGE_3D, S3_SAVAGE3D}, + {DEVICE_S3_INC_86C390_SAVAGE_3D_MV, S3_SAVAGE3D}, + /* Savage4 */ + {DEVICE_S3_INC_SAVAGE_4, S3_SAVAGE4}, + {DEVICE_S3_INC_SAVAGE_42, S3_SAVAGE4}, + /* SavageMX */ + {DEVICE_S3_INC_86C270_294_SAVAGE_MX_MV, S3_SAVAGE_MX}, + {DEVICE_S3_INC_82C270_294_SAVAGE_MX, S3_SAVAGE_MX}, + {DEVICE_S3_INC_86C270_294_SAVAGE_IX_MV, S3_SAVAGE_MX}, + /* SuperSavage */ + {DEVICE_S3_INC_SUPERSAVAGE_MX_128, S3_SUPERSAVAGE}, + {DEVICE_S3_INC_SUPERSAVAGE_MX_64, S3_SUPERSAVAGE}, + {DEVICE_S3_INC_SUPERSAVAGE_MX_64C, S3_SUPERSAVAGE}, + {DEVICE_S3_INC_SUPERSAVAGE_IX_128_SDR, S3_SUPERSAVAGE}, + {DEVICE_S3_INC_SUPERSAVAGE_IX_128_DDR, S3_SUPERSAVAGE}, + {DEVICE_S3_INC_SUPERSAVAGE_IX_64_SDR, S3_SUPERSAVAGE}, + {DEVICE_S3_INC_SUPERSAVAGE_IX_64_DDR, S3_SUPERSAVAGE}, + {DEVICE_S3_INC_SUPERSAVAGE_IX_C_SDR, S3_SUPERSAVAGE}, + {DEVICE_S3_INC_SUPERSAVAGE_IX_C_DDR, S3_SUPERSAVAGE}, + /* ProSavage */ + {DEVICE_S3_INC_PROSAVAGE_PM133, S3_PROSAVAGE}, + {DEVICE_S3_INC_PROSAVAGE_KM133, S3_PROSAVAGE}, + {DEVICE_S3_INC_86C380_PROSAVAGEDDR_K4M266, S3_PROSAVAGE}, + {DEVICE_S3_INC_VT8636A_PROSAVAGE_KN133, S3_PROSAVAGE}, + {DEVICE_S3_INC_VT8751_PROSAVAGEDDR_P4M266, S3_PROSAVAGE}, + {DEVICE_S3_INC_VT8375_PROSAVAGE8_KM266_KL266, S3_PROSAVAGE}, + /* Savage2000 */ + {DEVICE_S3_INC_86C410_SAVAGE_2000, S3_SAVAGE2000} +}; + +static unsigned int GetBlendForFourCC (int id) +{ + switch (id) + { + case IMGFMT_UYVY: + return 0; + case IMGFMT_YUY2: + return 1; + case IMGFMT_Y211: + return 4; + case IMGFMT_BGR15: + return 3; + case IMGFMT_BGR16: + return 5; + case IMGFMT_BGR24: + return 6; + case IMGFMT_BGR32: + return 7; + default: + return 1; + } +} + +static void S3SetColorOld (void) +{ + char sat = (info->eq.saturation + 1000) * 15 / 2000; + double hue = info->eq.hue * 3.1415926 / 1000.0; + char hsx = ((char) (sat * cos (hue))) & 0x1f; + char hsy = ((char) (sat * sin (hue))) & 0x1f; + + OUTREG (COLOR_ADJUSTMENT_REG, 0x80008000 | hsy << 24 | hsx << 16 | + ((info->eq.contrast + 1000) * 31 / 2000) << 8 | + (info->eq.brightness + 1000) * 255 / 2000); +} + +static void S3SetColorNew (void) +{ + /* not yet */ +} + +static void S3SetColor2000 (void) +{ + /* not yet */ +} + +static void S3SetColorKeyOld (void) +{ + int red, green, blue; + + /* Here, we reset the colorkey and all the controls */ + + red = (info->vidixcolorkey & 0x00FF0000) >> 16; + green = (info->vidixcolorkey & 0x0000FF00) >> 8; + blue = info->vidixcolorkey & 0x000000FF; + + if (!info->vidixcolorkey) + { + OUTREG (COL_CHROMA_KEY_CONTROL_REG, 0); + OUTREG (CHROMA_KEY_UPPER_BOUND_REG, 0); + OUTREG (BLEND_CONTROL_REG, 0); + } + else + { + switch (info->depth) + { + // FIXME: isnt fixed yet + case 8: + OUTREG (COL_CHROMA_KEY_CONTROL_REG, 0x37000000 | (info->vidixcolorkey & 0xFF)); + OUTREG (CHROMA_KEY_UPPER_BOUND_REG, 0x00000000 | (info->vidixcolorkey & 0xFF)); + break; + case 15: + /* 15 bpp 555 */ + red &= 0x1f; + green &= 0x1f; + blue &= 0x1f; + OUTREG (COL_CHROMA_KEY_CONTROL_REG, 0x05000000 | (red << 19) | (green << 11) | (blue << 3)); + OUTREG (CHROMA_KEY_UPPER_BOUND_REG, 0x00000000 | (red << 19) | (green << 11) | (blue << 3)); + break; + case 16: + /* 16 bpp 565 */ + red &= 0x1f; + green &= 0x3f; + blue &= 0x1f; + OUTREG (COL_CHROMA_KEY_CONTROL_REG, 0x16000000 | (red << 19) | (green << 10) | (blue << 3)); + OUTREG (CHROMA_KEY_UPPER_BOUND_REG, 0x00020002 | (red << 19) | (green << 10) | (blue << 3)); + break; + case 24: + /* 24 bpp 888 */ + OUTREG (COL_CHROMA_KEY_CONTROL_REG, 0x17000000 | (red << 16) | (green << 8) | (blue)); + OUTREG (CHROMA_KEY_UPPER_BOUND_REG, 0x00000000 | (red << 16) | (green << 8) | (blue)); + break; + } + + /* We use destination colorkey */ + OUTREG (BLEND_CONTROL_REG, 0x05000000); + } +} + +static void S3SetColorKeyNew (void) +{ + /* not yet */ +} + +static void S3SetColorKey2000 (void) +{ + /* not yet */ +} + +static void S3DisplayVideoOld (void) +{ + unsigned int ssControl; + int cr92; + + /* Set surface location and stride */ + OUTREG (SSTREAM_FBADDR0_REG, info->picture_offset); + OUTREG (SSTREAM_FBADDR1_REG, 0); + OUTREG (SSTREAM_STRIDE_REG, info->pitch); + /* Set window parameters */ + OUTREG (SSTREAM_WINDOW_START_REG, OS_XY (info->wx, info->wy)); + OUTREG (SSTREAM_WINDOW_SIZE_REG, OS_WH (info->drw_w, info->drw_h)); + + /* Set surface format and adjust scaling */ + if (info->chip.arch <= S3_VIRGE) + { + ssControl = ((info->src_w - 1) << 1) - ((info->drw_w - 1) & 0xffff); + ssControl |= GetBlendForFourCC (info->format) << 24; + if (info->src_w != info->drw_w) + ssControl |= 2 << 28; + + OUTREG (SSTREAM_CONTROL_REG, ssControl); + OUTREG (SSTREAM_STRETCH_REG, (((info->src_w - info->drw_w) & 0x7ff) << 16) | (info->src_w - 1)); + /* Calculate vertical scale factor */ + OUTREG (K1_VSCALE_REG, info->src_h - 1); + OUTREG (K2_VSCALE_REG, (info->src_h - info->drw_h) & 0x7ff); + OUTREG (DDA_VERT_REG, (1 - info->drw_h) & 0xfff); + } + else + { + ssControl = GetBlendForFourCC (info->format) << 24 | info->src_w; + if (info->src_w > (info->drw_w << 1)) + { + /* BUGBUG shouldn't this be >=? */ + if (info->src_w <= (info->drw_w << 2)) + ssControl |= HDSCALE_4; + else if (info->src_w > (info->drw_w << 3)) + ssControl |= HDSCALE_8; + else if (info->src_w > (info->drw_w << 4)) + ssControl |= HDSCALE_16; + else if (info->src_w > (info->drw_w << 5)) + ssControl |= HDSCALE_32; + else if (info->src_w > (info->drw_w << 6)) + ssControl |= HDSCALE_64; + } + + OUTREG (SSTREAM_CONTROL_REG, ssControl); + OUTREG (SSTREAM_STRETCH_REG, (info->src_w << 15) / info->drw_w); + OUTREG (SSTREAM_LINES_REG, info->src_h); + /* Calculate vertical scale factor. */ + OUTREG (SSTREAM_VSCALE_REG, VSCALING (info->src_h, info->drw_h)); + } + + if (info->chip.arch == S3_TRIO64V) + OUTREG (STREAMS_FIFO_REG, (6 << 10) | (14 << 5) | 16); + else + { + // FIXME: this should actually be enabled + info->pitch = (info->pitch + 7) / 8; + VGAOUT8 (vgaCRIndex, 0x92); + cr92 = VGAIN8 (vgaCRReg); + VGAOUT8 (vgaCRReg, (cr92 & 0x40) | (info->pitch >> 8) | 0x80); + VGAOUT8 (vgaCRIndex, 0x93); + VGAOUT8 (vgaCRReg, info->pitch); + OUTREG (STREAMS_FIFO_REG, 2 | 25 << 5 | 32 << 11); + } +} + +static void S3DisplayVideoNew (void) +{ + /* not yet */ +} + +static void S3DisplayVideo2000 (void) +{ + /* not yet */ +} + +static void S3InitStreamsOld (void) +{ + /*unsigned long jDelta; */ + unsigned long format = 0; + + /*jDelta = pScrn->displayWidth * (pScrn->bitsPerPixel + 7) / 8; */ + switch (info->depth) + { + case 8: + format = 0 << 24; + break; + case 15: + format = 3 << 24; + break; + case 16: + format = 5 << 24; + break; + case 24: + format = 7 << 24; + break; + } +//#warning enable this again + OUTREG (PSTREAM_FBSIZE_REG, info->screen_y * info->screen_x * (info->bpp >> 3)); + OUTREG (PSTREAM_WINDOW_START_REG, OS_XY (0, 0)); + OUTREG (PSTREAM_WINDOW_SIZE_REG, OS_WH (info->screen_x, info->screen_y)); + OUTREG (PSTREAM_FBADDR1_REG, 0); + /*OUTREG( PSTREAM_STRIDE_REG, jDelta ); */ + OUTREG (PSTREAM_CONTROL_REG, format); + OUTREG (PSTREAM_FBADDR0_REG, 0); + + OUTREG (COL_CHROMA_KEY_CONTROL_REG, 0); + OUTREG (SSTREAM_CONTROL_REG, 0); + OUTREG (CHROMA_KEY_UPPER_BOUND_REG, 0); + OUTREG (SSTREAM_STRETCH_REG, 0); + OUTREG (COLOR_ADJUSTMENT_REG, 0); + OUTREG (BLEND_CONTROL_REG, 1 << 24); + OUTREG (DOUBLE_BUFFER_REG, 0); + OUTREG (SSTREAM_FBADDR0_REG, 0); + OUTREG (SSTREAM_FBADDR1_REG, 0); + OUTREG (SSTREAM_FBADDR2_REG, 0); + OUTREG (SSTREAM_FBSIZE_REG, 0); + OUTREG (SSTREAM_STRIDE_REG, 0); + OUTREG (SSTREAM_VSCALE_REG, 0); + OUTREG (SSTREAM_LINES_REG, 0); + OUTREG (SSTREAM_VINITIAL_REG, 0); +} + +static void S3InitStreamsNew (void) +{ + /* not yet */ +} + +static void S3InitStreams2000 (void) +{ + /* not yet */ +} + +static void S3StreamsOn (void) +{ + unsigned char jStreamsControl; + + VGAOUT8 (vgaCRIndex, EXT_MISC_CTRL2); + + if (S3_SAVAGE_MOBILE_SERIES (info->chip.arch)) + { + jStreamsControl = VGAIN8 (vgaCRReg) | ENABLE_STREAM1; + VerticalRetraceWait (); + VGAOUT16 (vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2); + + S3InitStreams = S3InitStreamsNew; + S3SetColor = S3SetColorNew; + S3SetColorKey = S3SetColorKeyNew; + S3DisplayVideo = S3DisplayVideoNew; + } + else if (info->chip.arch == S3_SAVAGE2000) + { + jStreamsControl = VGAIN8 (vgaCRReg) | ENABLE_STREAM1; + VerticalRetraceWait (); + VGAOUT16 (vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2); + + S3InitStreams = S3InitStreams2000; + S3SetColor = S3SetColor2000; + S3SetColorKey = S3SetColorKey2000; + S3DisplayVideo = S3DisplayVideo2000; + } + else + { + jStreamsControl = VGAIN8 (vgaCRReg) | ENABLE_STREAMS_OLD; + VerticalRetraceWait (); + VGAOUT16 (vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2); + + S3InitStreams = S3InitStreamsOld; + S3SetColor = S3SetColorOld; + S3SetColorKey = S3SetColorKeyOld; + S3DisplayVideo = S3DisplayVideoOld; + } + + S3InitStreams (); + + VerticalRetraceWait (); + /* Turn on secondary stream TV flicker filter, once we support TV. */ + /* SR70 |= 0x10 */ +} + +static void S3GetScrProp (struct s3_info *info) +{ + unsigned char bpp = 0; + + VGAOUT8 (vgaCRIndex, EXT_MISC_CTRL2); + bpp = VGAIN8 (vgaCRReg); + + switch (bpp & 0xf0) + { + case 0x00: + case 0x10: + info->depth = 8; + info->bpp = 8; + break; + case 0x20: + case 0x30: + info->depth = 15; + info->bpp = 16; + break; + case 0x40: + case 0x50: + info->depth = 16; + info->bpp = 16; + break; + case 0x70: + case 0xd0: + info->depth = 24; + info->bpp = 32; + break; + } + + VGAOUT8 (vgaCRIndex, 0x1); + info->screen_x = (1 + VGAIN8 (vgaCRReg)) << 3; + VGAOUT8 (vgaCRIndex, 0x12); + info->screen_y = VGAIN8 (vgaCRReg); + VGAOUT8 (vgaCRIndex, 0x07); + info->screen_y |= (VGAIN8 (vgaCRReg) & 0x02) << 7; + info->screen_y |= (VGAIN8 (vgaCRReg) & 0x40) << 3; + ++info->screen_y; + + printf ("[s3_vid] x = %d, y = %d, bpp = %d\n", info->screen_x, info->screen_y, info->bpp); +} + +static void S3StreamsOff (void) +{ + unsigned char jStreamsControl; + + if (info->chip.arch == S3_TRIO64V) + OUTREG (STREAMS_FIFO_REG, (20 << 10)); + + VGAOUT8 (vgaCRIndex, EXT_MISC_CTRL2); + if (S3_SAVAGE_MOBILE_SERIES (info->chip.arch) || + (info->chip.arch == S3_SUPERSAVAGE) || (info->chip.arch == S3_SAVAGE2000)) + jStreamsControl = VGAIN8 (vgaCRReg) & NO_STREAMS; + else + jStreamsControl = VGAIN8 (vgaCRReg) & NO_STREAMS_OLD; + + VerticalRetraceWait (); + VGAOUT16 (vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2); + + if (S3_SAVAGE_SERIES (info->chip.arch)) + { + VGAOUT16 (vgaCRIndex, 0x0093); + VGAOUT8 (vgaCRIndex, 0x92); + VGAOUT8 (vgaCRReg, VGAIN8 (vgaCRReg) & 0x40); + } +} + +static int find_chip (unsigned chip_id) +{ + unsigned i; + + for (i = 0; i < sizeof (s3_card_ids) / sizeof (struct s3_cards); i++) + if (chip_id == s3_card_ids[i].chip_id) + return i; + return -1; +} + +static int s3_probe (int verbose, int force) +{ + pciinfo_t lst[MAX_PCI_DEVICES]; + unsigned i, num_pci; + int err; + + if (force) + printf ("[s3_vid] Warning: forcing not supported yet!\n"); + err = pci_scan (lst, &num_pci); + if (err) + { + printf ("[s3_vid] Error occurred during pci scan: %s\n", strerror (err)); + return err; + } + else + { + err = ENXIO; + for (i = 0; i < num_pci; i++) + { + if (lst[i].vendor == VENDOR_S3_INC) + { + int idx; + const char *dname; + idx = find_chip (lst[i].device); + if (idx == -1) + continue; + dname = pci_device_name (lst[i].vendor, lst[i].device); + dname = dname ? dname : "Unknown chip"; + printf ("[s3_vid] Found chip: %s\n", dname); + // FIXME: whats wrong here? + if ((lst[i].command & PCI_COMMAND_IO) == 0) + { + printf ("[s3_vid] Device is disabled, ignoring\n"); + continue; + } + s3_cap.device_id = lst[i].device; + err = 0; + memcpy (&pci_info, &lst[i], sizeof (pciinfo_t)); + break; + } + } + } + if (err && verbose) + printf ("[s3_vid] Can't find chip\n"); + return err; +} + +static int s3_init (const char *args __attribute__ ((unused))) +{ + unsigned char cr36; + int mtrr, videoRam; + static unsigned char RamTrioVirge[] = { 4, 0, 3, 8, 2, 6, 1, 0 }; + static unsigned char RamSavage3D[] = { 8, 4, 4, 2 }; + static unsigned char RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 }; + static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; + static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 }; + + enable_app_io (); + + info = calloc (1, sizeof (s3_info)); + + info->chip.arch = s3_card_ids[find_chip (pci_info.device)].arch; + + /* Switch to vga registers */ + OUTPORT8 (0x3c3, INPORT8 (0x3c3) | 0x01); + OUTPORT8 (0x3c2, INPORT8 (0x3cc) | 0x01); + /* Unlock extended registers */ + OUTPORT8 (vgaCRIndex, 0x38); + OUTPORT8 (vgaCRReg, 0x48); + OUTPORT8 (vgaCRIndex, 0x39); + OUTPORT8 (vgaCRReg, 0xa0); + + if (info->chip.arch <= S3_VIRGE) + { + /* TODO: Improve detecting code */ + + /* Enable LFB */ + OUTPORT8 (vgaCRIndex, LIN_ADDR_CTRL); + OUTPORT8 (vgaCRReg, INPORT8 (vgaCRReg) | ENABLE_LFB); + /* Enable NewMMIO */ + OUTPORT8 (vgaCRIndex, EXT_MEM_CTRL1); + OUTPORT8 (vgaCRReg, INPORT8 (vgaCRReg) | ENABLE_NEWMMIO); + } + + if (info->chip.arch < S3_SAVAGE3D) + info->control_base = map_phys_mem (pci_info.base0 + S3_NEWMMIO_REGBASE, S3_NEWMMIO_REGSIZE); + else if (info->chip.arch == S3_SAVAGE3D) + info->control_base = map_phys_mem (pci_info.base0 + S3_NEWMMIO_REGBASE, S3_NEWMMIO_REGSIZE_SAVAGE); + else + info->control_base = map_phys_mem (pci_info.base0, S3_NEWMMIO_REGSIZE_SAVAGE); + + /* Unlock CRTC[0-7] */ + VGAOUT8 (vgaCRIndex, 0x11); + VGAOUT8 (vgaCRReg, VGAIN8 (vgaCRReg) & 0x7f); + /* Unlock sequencer */ + VGAOUT16 (0x3c4, 0x0608); + /* Detect amount of installed ram */ + VGAOUT8 (vgaCRIndex, 0x36); + cr36 = VGAIN8 (vgaCRReg); + + switch (info->chip.arch) + { + case S3_TRIO64V: + case S3_VIRGE: + videoRam = RamTrioVirge[(cr36 & 0xE0) >> 5] * 1024; + break; + + case S3_SAVAGE3D: + videoRam = RamSavage3D[(cr36 & 0xC0) >> 6] * 1024; + break; + + case S3_SAVAGE4: + /* + * The Savage4 has one ugly special case to consider. On + * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB + * when it really means 8MB. Why do it the same when you + * can do it different... + */ + VGAOUT8 (vgaCRIndex, 0x68); + if ((VGAIN8 (vgaCRReg) & 0xC0) == (0x01 << 6)) + RamSavage4[1] = 8; + + case S3_SAVAGE2000: + videoRam = RamSavage4[(cr36 & 0xE0) >> 5] * 1024; + break; + + case S3_SAVAGE_MX: + videoRam = RamSavageMX[(cr36 & 0x0E) >> 1] * 1024; + break; + + case S3_PROSAVAGE: + videoRam = RamSavageNB[(cr36 & 0xE0) >> 5] * 1024; + break; + + default: + /* How did we get here? */ + videoRam = 0; + break; + } + + printf ("[s3_vid] VideoRam = %d\n", videoRam); + info->chip.fbsize = videoRam * 1024; + + if (info->chip.arch <= S3_SAVAGE3D) + mtrr = mtrr_set_type (pci_info.base0, info->chip.fbsize, MTRR_TYPE_WRCOMB); + else + mtrr = mtrr_set_type (pci_info.base1, info->chip.fbsize, MTRR_TYPE_WRCOMB); + + if (mtrr != 0) + printf ("[s3_vid] Unable to setup MTRR: %s\n", strerror (mtrr)); + else + printf ("[s3_vid] MTRR set up\n"); + + S3GetScrProp (info); + S3StreamsOn (); + + return 0; +} + +static void s3_destroy (void) +{ + unmap_phys_mem (info->video_base, info->chip.fbsize); + if (S3_SAVAGE_SERIES (info->chip.arch)) + unmap_phys_mem (info->control_base, S3_NEWMMIO_REGSIZE_SAVAGE); + else + unmap_phys_mem (info->control_base, S3_NEWMMIO_REGSIZE); + + free (info); +} + +static int s3_get_caps (vidix_capability_t * to) +{ + memcpy (to, &s3_cap, sizeof (vidix_capability_t)); + return 0; +} + +static int is_supported_fourcc (uint32_t fourcc) +{ + switch (fourcc) + { +//FIXME: Burst Command Interface should be used +// for planar to packed conversion +// case IMGFMT_YV12: +// case IMGFMT_I420: + case IMGFMT_UYVY: + case IMGFMT_YUY2: + case IMGFMT_Y211: + case IMGFMT_BGR15: + case IMGFMT_BGR16: + case IMGFMT_BGR24: + case IMGFMT_BGR32: + return 1; + default: + return 0; + } +} + +static int s3_query_fourcc (vidix_fourcc_t * to) +{ + if (is_supported_fourcc (to->fourcc)) + { + to->depth = VID_DEPTH_ALL; + to->flags = VID_CAP_EXPAND | VID_CAP_SHRINK | VID_CAP_COLORKEY; + return 0; + } + else + to->depth = to->flags = 0; + + return ENOSYS; +} + +#if 0 +static int s3_get_gkeys (vidix_grkey_t * grkey) +{ + return 0; +} +#endif + +static int s3_set_gkeys (const vidix_grkey_t * grkey) +{ + if (grkey->ckey.op == CKEY_FALSE) + { + info->use_colorkey = 0; + info->vidixcolorkey = 0; + printf ("[s3_vid] Colorkeying disabled\n"); + } + else + { + info->use_colorkey = 1; + info->vidixcolorkey = ((grkey->ckey.red << 16) | (grkey->ckey.green << 8) | grkey->ckey.blue); + printf ("[s3_vid] Set colorkey 0x%x\n", info->vidixcolorkey); + } + if (S3SetColorKey) + S3SetColorKey (); + return 0; +} + +static int s3_get_eq (vidix_video_eq_t * eq) +{ + memcpy (eq, &(info->eq), sizeof (vidix_video_eq_t)); + return 0; +} + +static int s3_set_eq (const vidix_video_eq_t * eq) +{ + if (eq->cap & VEQ_CAP_BRIGHTNESS) + info->eq.brightness = eq->brightness; + if (eq->cap & VEQ_CAP_CONTRAST) + info->eq.contrast = eq->contrast; + if (eq->cap & VEQ_CAP_SATURATION) + info->eq.saturation = eq->saturation; + if (eq->cap & VEQ_CAP_HUE) + info->eq.hue = eq->hue; + if (S3SetColor) + S3SetColor (); + return 0; +} + +static int s3_config_playback (vidix_playback_t * vinfo) +{ + unsigned int i, bpp; + + if (!is_supported_fourcc (vinfo->fourcc)) + return -1; + + info->src_w = vinfo->src.w; + info->src_h = vinfo->src.h; + + info->drw_w = vinfo->dest.w; + info->drw_h = vinfo->dest.h; + + info->wx = vinfo->dest.x; + info->wy = vinfo->dest.y; + info->format = vinfo->fourcc; + + info->eq.cap = VEQ_CAP_BRIGHTNESS | VEQ_CAP_CONTRAST | + VEQ_CAP_SATURATION | VEQ_CAP_HUE; + info->eq.brightness = 0; + info->eq.contrast = 0; + info->eq.saturation = 0; + info->eq.hue = 0; + + vinfo->offset.y = 0; + vinfo->offset.v = 0; + vinfo->offset.u = 0; + + vinfo->dest.pitch.y = 32; + vinfo->dest.pitch.u = 32; + vinfo->dest.pitch.v = 32; + + switch (vinfo->fourcc) + { + case IMGFMT_Y211: + bpp = 1; + break; + case IMGFMT_BGR24: + bpp = 3; + break; + case IMGFMT_BGR32: + bpp = 4; + break; + default: + bpp = 2; + break; + } + + info->pitch = ((info->src_w * bpp) + 15) & ~15; + info->pitch |= ((info->pitch / bpp) << 16); + + vinfo->frame_size = (info->pitch & 0xffff) * info->src_h; + info->frame_size = vinfo->frame_size; + + info->picture_offset = info->screen_x * info->screen_y * (info->bpp >> 3); + if (info->picture_offset > (info->chip.fbsize - vinfo->frame_size)) + { + printf ("[s3_vid] Not enough memory for overlay\n"); + return -1; + } + + if (info->chip.arch <= S3_SAVAGE3D) + info->video_base = map_phys_mem (pci_info.base0, info->chip.fbsize); + else + info->video_base = map_phys_mem (pci_info.base1, info->chip.fbsize); + + if (info->video_base == NULL) + { + printf ("[s3_vid] errno = %s\n", strerror (errno)); + return -1; + } + + info->picture_base = (uint32_t) info->video_base + info->picture_offset; + + vinfo->dga_addr = (void *) (info->picture_base); + + vinfo->num_frames = (info->chip.fbsize - info->picture_offset) / vinfo->frame_size; + if (vinfo->num_frames > VID_PLAY_MAXFRAMES) + vinfo->num_frames = VID_PLAY_MAXFRAMES; + + for (i = 0; i < vinfo->num_frames; i++) + vinfo->offsets[i] = vinfo->frame_size * i; + + return 0; +} + +static int s3_playback_on (void) +{ + S3DisplayVideo (); + return 0; +} + +static int s3_playback_off (void) +{ + S3StreamsOff (); + return 0; +} + +static int s3_frame_sel (unsigned int frame) +{ + OUTREG (SSTREAM_FBADDR0_REG, info->picture_offset + (info->frame_size * frame)); + return 0; +} + +VDXDriver s3_drv = { + "s3", + NULL, + .probe = s3_probe, + .get_caps = s3_get_caps, + .query_fourcc = s3_query_fourcc, + .init = s3_init, + .destroy = s3_destroy, + .config_playback = s3_config_playback, + .playback_on = s3_playback_on, + .playback_off = s3_playback_off, + .frame_sel = s3_frame_sel, + .get_eq = s3_get_eq, + .set_eq = s3_set_eq, + .set_gkey = s3_set_gkeys, +}; |