📄 vid_1400.c
字号:
/*-----------------------------------------------------------------------------
* VID_1400.C
*
* Version 2.0 - February 21, 2000
*
* This file contains routines to control the SC1400 video overlay hardware.
*
* History:
* Versions 0.1 through 2.0 by Brian Falardeau.
*
* Copyright (c) 1999-2000 National Semiconductor.
*-----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* SC1400 PLL TABLE
*----------------------------------------------------------------------------
*/
typedef struct tagSC1400PLL
{
long frequency; /* 16.16 fixed point frequency */
unsigned long clock_select; /* clock select register (0x2C) */
} SC1400PLL;
SC1400PLL gfx_sc1400_clock_table[] = {
{ 0x00192CCC, 0x00000000 }, /* 25.1750 */
{ 0x001C526E, 0x00010000 }, /* 28.3220 */
{ 0x001F8000, 0x00020000 }, /* 31.5000 */
{ 0x00240000, 0x000E0000 }, /* 36.0000 */
{ 0x00258000, 0x0010110C }, /* 37.5000 */
{ 0x00280000, 0x00040000 }, /* 40.0000 */
{ 0x002CE666, 0x00090000 }, /* 44.9000 */
{ 0x00320000, 0x00100C06 }, /* 50.0000 */
{ 0x00325999, 0x0050600C }, /* 50.3500 */
{ 0x00360000, 0x00100100 }, /* 54.0000 */
{ 0x0038643F, 0x0010160A }, /* 56.3916 */
{ 0x0038A3D7, 0x00506C0C }, /* 56.6440 */
{ 0x003B0000, 0x0010170A }, /* 59.6583 */
{ 0x003BA886, 0x00100A04 }, /* 59.6583 */
{ 0x003F0000, 0x00100602 }, /* 63.0000 */
{ 0x00410000, 0x00060000 }, /* 65.0000 */
{ 0x00438000, 0x00100401 }, /* 67.5000 */
{ 0x0046CCCC, 0x00101407 }, /* 70.8000 */
{ 0x00480000, 0x00100702 }, /* 72.0000 */
{ 0x004B0000, 0x00070000 }, /* 75.0000 */
{ 0x004EC000, 0x0010220B }, /* 78.7500 */
{ 0x00500000, 0x00304C0C }, /* 80.0000 */
{ 0x00510000, 0x00100200 }, /* 81.0000 */
{ 0x00550000, 0x00080000 }, /* 85.0000 */
{ 0x0059CCCC, 0x00100902 }, /* 89.8000 */
{ 0x00630000, 0x00100A02 }, /* 99.0000 */
{ 0x00640000, 0x00102409 }, /* 100.0000 */
{ 0x006C0000, 0x00100300 }, /* 108.0000 */
{ 0x00870000, 0x00050000 }, /* 135.0000 */
{ 0x009D8000, 0x00102205 }, /* 157.5000 */
{ 0x00A20000, 0x00100500 }, /* 162.0000 */
{ 0x00AA0000, 0x000B0000 }, /* 170.0000 */
{ 0x00AF0000, 0x00100C01 }, /* 175.0000 */
{ 0x00BD0000, 0x00100600 }, /* 189.0000 */
{ 0x00CA0000, 0x00100E01 }, /* 202.0000 */
{ 0x00E80000, 0x00102A04 }, /* 232.0000 */
};
#define NUM_SC1400_FREQUENCIES sizeof(gfx_sc1400_clock_table)/sizeof(SC1400PLL)
/*---------------------------------------------------------------------------
* gfx_reset_video (PRIVATE ROUTINE: NOT PART OF DURANGO API)
*
* This routine is used to disable all components of video overlay before
* performing a mode switch.
*---------------------------------------------------------------------------
*/
#if GFX_VIDEO_DYNAMIC
void sc1400_reset_video(void)
#else
void gfx_reset_video(void)
#endif
{
gfx_set_video_enable(0);
}
/*---------------------------------------------------------------------------
* gfx_set_clock_frequency
*
* This routine sets the clock frequency, specified as a 16.16 fixed point
* value (0x00318000 = 49.5 MHz). It will set the closest frequency found
* in the lookup table.
*---------------------------------------------------------------------------
*/
#if GFX_VIDEO_DYNAMIC
void sc1400_set_clock_frequency(unsigned long frequency)
#else
void gfx_set_clock_frequency(unsigned long frequency)
#endif
{
int index;
unsigned long value;
long min, diff;
/* FIND THE REGISTER VALUES FOR THE DESIRED FREQUENCY */
/* Search the table for the closest frequency (16.16 format). */
value = gfx_sc1400_clock_table[0].clock_select;
min = (long) gfx_sc1400_clock_table[0].frequency - frequency;
if (min < 0L) min = -min;
for (index = 1; index < NUM_SC1400_FREQUENCIES; index++)
{
diff = (long) gfx_sc1400_clock_table[index].frequency - frequency;
if (diff < 0L) diff = -diff;
if (diff < min)
{
min = diff;
value = gfx_sc1400_clock_table[index].clock_select;
}
}
/* SET THE DOT CLOCK REGISTER */
WRITE_VID32(SC1400_VID_MISC, 0x00001000);
WRITE_VID32(SC1400_VID_CLOCK_SELECT, value);
return;
}
/*-----------------------------------------------------------------------------
* gfx_set_video_enable
*
* This routine enables or disables the video overlay functionality.
*-----------------------------------------------------------------------------
*/
#if GFX_VIDEO_DYNAMIC
int sc1400_set_video_enable(int enable)
#else
int gfx_set_video_enable(int enable)
#endif
{
unsigned long vcfg;
/* WAIT FOR VERTICAL BLANK TO START */
/* Otherwise a glitch can be observed. */
if (gfx_test_timing_active())
{
if (!gfx_test_vertical_active())
{
while(!gfx_test_vertical_active());
}
while(gfx_test_vertical_active());
}
vcfg = READ_VID32(SC1400_VIDEO_CONFIG);
if (enable)
{
/* ENABLE VIDEO OVERLAY FROM DISPLAY CONTROLLER */
/* Use private routine to abstract the display controller. */
gfx_set_display_video_enable(1);
/* SET SC1400 BUS CONTROL PARAMETERS */
/* Currently always high speed, 8-bit interface. */
vcfg |= SC1400_VCFG_HIGH_SPD_INT;
vcfg &= ~(SC1400_VCFG_EARLY_VID_RDY | SC1400_VCFG_16_BIT_EN);
/* ENABLE SC1400 VIDEO OVERLAY */
vcfg |= SC1400_VCFG_VID_EN;
WRITE_VID32(SC1400_VIDEO_CONFIG, vcfg);
}
else
{
/* DISABLE SC1400 VIDEO OVERLAY */
vcfg &= ~SC1400_VCFG_VID_EN;
WRITE_VID32(SC1400_VIDEO_CONFIG, vcfg);
/* DISABLE VIDEO OVERLAY FROM DISPLAY CONTROLLER */
/* Use private routine to abstract the display controller. */
gfx_set_display_video_enable(0);
}
return(0);
}
/*-----------------------------------------------------------------------------
* gfx_set_video_format
*
* Currently only sets 4:2:0 format, Y1 V Y0 U.
*-----------------------------------------------------------------------------
*/
#if GFX_VIDEO_DYNAMIC
int sc1400_set_video_format(unsigned long format)
#else
int gfx_set_video_format(unsigned long format)
#endif
{
unsigned long vcfg = 0;
/* SET THE SC1400 VIDEO INPUT FORMAT */
vcfg = READ_VID32(SC1400_VIDEO_CONFIG);
vcfg &= ~(SC1400_VCFG_VID_INP_FORMAT | SC1400_VCFG_4_2_0_MODE);
vcfg &= ~(SC1400_VCFG_CSC_BYPASS);
if (format < 4) vcfg |= (format << 2);
else vcfg |= SC1400_VCFG_CSC_BYPASS;
WRITE_VID32(SC1400_VIDEO_CONFIG, vcfg);
return(0);
}
/*-----------------------------------------------------------------------------
* gfx_set_video_size
*
* This routine specifies the size of the source data. It is used only
* to determine how much data to transfer per frame, and is not used to
* calculate the scaling value (that is handled by a separate routine).
*-----------------------------------------------------------------------------
*/
#if GFX_VIDEO_DYNAMIC
int sc1400_set_video_size(unsigned short width, unsigned short height)
#else
int gfx_set_video_size(unsigned short width, unsigned short height)
#endif
{
unsigned long size, vcfg;
/* SET THE SC1400 VIDEO LINE SIZE */
vcfg = READ_VID32(SC1400_VIDEO_CONFIG);
vcfg &= ~(SC1400_VCFG_LINE_SIZE_LOWER_MASK | SC1400_VCFG_LINE_SIZE_UPPER);
size = (width >> 1);
vcfg |= (size & 0x00FF) << 8;
if (size & 0x0100) vcfg |= SC1400_VCFG_LINE_SIZE_UPPER;
WRITE_VID32(SC1400_VIDEO_CONFIG, vcfg);
/* SET TOTAL VIDEO BUFFER SIZE IN DISPLAY CONTROLLER */
/* Use private routine to abstract the display controller. */
gfx_set_display_video_size(width, height);
return(0);
}
/*-----------------------------------------------------------------------------
* gfx_set_video_offset
*
* This routine sets the starting offset for the video buffer when only
* one offset needs to be specified.
*-----------------------------------------------------------------------------
*/
#if GFX_VIDEO_DYNAMIC
int sc1400_set_video_offset(unsigned long offset)
#else
int gfx_set_video_offset(unsigned long offset)
#endif
{
/* SAVE VALUE FOR FUTURE CLIPPING OF THE TOP OF THE VIDEO WINDOW */
gfx_vid_offset = offset;
/* SET VIDEO BUFFER OFFSET IN DISPLAY CONTROLLER */
/* Use private routine to abstract the display controller. */
gfx_set_display_video_offset(offset);
return(0);
}
/*---------------------------------------------------------------------------
* gfx_set_video_scale
*
* This routine sets the scale factor for the video overlay window. The
* size of the source and destination regions are specified in pixels.
*---------------------------------------------------------------------------
*/
#if GFX_VIDEO_DYNAMIC
int sc1400_set_video_scale(unsigned short srcw, unsigned short srch,
unsigned short dstw, unsigned short dsth)
#else
int gfx_set_video_scale(unsigned short srcw, unsigned short srch,
unsigned short dstw, unsigned short dsth)
#endif
{
unsigned long xscale, yscale;
/* SAVE PARAMETERS */
/* These are needed for clipping the video window later. */
gfx_vid_srcw = srcw;
gfx_vid_srch = srch;
gfx_vid_dstw = dstw;
gfx_vid_dsth = dsth;
/* CALCULATE SC1400 SCALE FACTORS */
/* No downscaling in SC1400 so force to 1x if attempted. */
if (srcw < dstw) xscale = (0x2000 * (srcw - 1)) / (dstw - 1);
else xscale = 0x1FFF;
if (srch < dsth) yscale = (0x2000 * (srch - 1)) / (dsth - 1);
else yscale = 0x1FFF;
WRITE_VID32(SC1400_VIDEO_SCALE, (yscale << 16) | xscale);
/* CALL ROUTINE TO UPDATE WINDOW POSITION */
/* This is required because the scale values effect the number of */
/* source data pixels that need to be clipped, as well as the */
/* amount of data that needs to be transferred. */
gfx_set_video_window(gfx_vid_xpos, gfx_vid_ypos, gfx_vid_width,
gfx_vid_height);
return(0);
}
/*---------------------------------------------------------------------------
* gfx_set_video_window
*
* This routine sets the position and size of the video overlay window. The
* position is specified in screen relative coordinates, and may be negative.
* The size of destination region is specified in pixels. The line size
* indicates the number of bytes of source data per scanline.
*---------------------------------------------------------------------------
*/
#if GFX_VIDEO_DYNAMIC
int sc1400_set_video_window(short x, short y, unsigned short w,
unsigned short h)
#else
int gfx_set_video_window(short x, short y, unsigned short w,
unsigned short h)
#endif
{
unsigned long vcfg = 0;
unsigned long hadjust, vadjust;
unsigned long initread;
unsigned long xstart, ystart, xend, yend;
unsigned long offset, line_size;
/* SAVE PARAMETERS */
/* These are needed to call this routine if the scale value changes. */
gfx_vid_xpos = x;
gfx_vid_ypos = y;
gfx_vid_width = w;
gfx_vid_height = h;
/* GET ADJUSTMENT VALUES */
/* Use routines to abstract version of display controller. */
hadjust = gfx_get_htotal() - gfx_get_hsync_end() - 13;
vadjust = gfx_get_vtotal() - gfx_get_vsync_end() + 1;
if (x > 0)
{
/* NO CLIPPING ON LEFT */
xstart = x + hadjust;
initread = 0;
}
else
{
/* CLIPPING ON LEFT */
/* Adjust initial read for scale, checking for divide by zero */
xstart = hadjust;
initread = -x;
if (gfx_vid_dstw)
initread = ((-x) * gfx_vid_srcw) / gfx_vid_dstw;
else initread = 0;
}
/* CLIPPING ON RIGHT */
xend = x + w;
if (xend > gfx_get_hactive()) xend = gfx_get_hactive();
xend += hadjust;
/* CLIPPING ON TOP */
offset = gfx_vid_offset;
if (y >= 0)
{
ystart = y + vadjust;
}
else
{
ystart = vadjust;
line_size = (READ_VID32(SC1400_VIDEO_CONFIG) >> 7) & 0x000001FE;
if (READ_VID32(SC1400_VIDEO_CONFIG) & SC1400_VCFG_LINE_SIZE_UPPER)
line_size += 512;
if (gfx_vid_dsth)
offset = gfx_vid_offset + (line_size << 1) *
(((-y) * gfx_vid_srch) / gfx_vid_dsth);
}
/* CLIPPING ON BOTTOM */
yend = y + h;
if (yend >= gfx_get_vactive()) yend = gfx_get_vactive();
yend += vadjust;
/* SET VIDEO BUFFER OFFSET IN DISPLAY CONTROLLER */
/* Use private routine to abstract the display controller. */
gfx_set_display_video_offset(offset);
/* DISABLE REGISTER UPDATES */
vcfg = READ_VID32(SC1400_VIDEO_CONFIG);
vcfg &= ~SC1400_VCFG_VID_REG_UPDATE;
WRITE_VID32(SC1400_VIDEO_CONFIG, vcfg);
/* SET VIDEO POSITION */
WRITE_VID32(SC1400_VIDEO_X_POS, (xend << 16) | xstart);
WRITE_VID32(SC1400_VIDEO_Y_POS, (yend << 16) | ystart);
/* SET INITIAL READ ADDRESS AND ENABLE REGISTER UPDATES */
vcfg &= ~SC1400_VCFG_INIT_READ_MASK;
vcfg |= (initread << 15) & SC1400_VCFG_INIT_READ_MASK;
vcfg |= SC1400_VCFG_VID_REG_UPDATE;
WRITE_VID32(SC1400_VIDEO_CONFIG, vcfg);
return(0);
}
/*---------------------------------------------------------------------------
* gfx_set_video_color_key
*
* This routine specifies the color key value and mask for the video overlay
* hardware. To disable color key, the color and mask should both be set to
* zero. The hardware uses the color key in the following equation:
*
* ((source data) & (color key mask)) == ((color key) & (color key mask))
*
* The source data can be either graphics data or video data. The bluescreen
* parameter is set to have the hardware compare video data and clear to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -