📄 cim_vg.c
字号:
tv_mode.mode_height = tv_mode.vactive;
return vg_set_custom_mode (&tv_mode, bpp);
}
return CIM_STATUS_ERROR;
}
/*---------------------------------------------------------------------------
* vg_set_custom_mode
*
* This routine sets a display mode. The API is structured such that this routine
* can be called from four sources:
* - vg_set_display_mode
* - vg_set_panel_mode
* - vg_set_tv_mode
* - directly by the user for a custom mode.
*---------------------------------------------------------------------------*/
int vg_set_custom_mode (VG_DISPLAY_MODE *mode_params, int bpp)
{
unsigned long config, misc, temp;
unsigned long irq_ctl, genlk_ctl;
unsigned long unlock, flags;
unsigned long acfg, gcfg, dcfg;
unsigned long size, line_size, pitch;
unsigned long bpp_mask, dv_size;
unsigned long hscale, vscale, starting_width;
unsigned long starting_height, output_height;
Q_WORD msr_value;
/* DETERMINE DIMENSIONS FOR SCALING */
/* Scaling is performed before flicker filtering and interlacing */
output_height = mode_params->vactive;
if (mode_params->flags & VG_MODEFLAG_INTERLACED)
{
/* EVEN AND ODD FIELDS ARE SEPARATE */
/* The composite image height is the sum of the height of both fields */
if ((mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_FLICKER ||
(mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_ADDRESS)
{
output_height += mode_params->vactive_even;
}
/* LINE DOUBLING */
/* The composite image height is the greater of the two field heights. */
else if (mode_params->vactive_even > output_height)
output_height = mode_params->vactive_even;
}
/* CHECK FOR VALID SCALING FACTOR */
/* GeodeLX supports only 2:1 vertical downscale (before interlacing) and */
/* 2:1 horizontal downscale. The source width when scaling must be */
/* less than or equal to 1024 pixels. The destination can be any size, */
/* except when flicker filtering is enabled. */
irq_ctl = 0;
if (mode_params->flags & VG_MODEFLAG_PANELOUT)
{
if (mode_params->src_width != mode_params->mode_width)
{
starting_width = (mode_params->hactive * mode_params->src_width) / mode_params->mode_width;
hscale = (mode_params->src_width << 14) / (mode_params->mode_width - 1);
irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
}
else
{
starting_width = mode_params->hactive;
hscale = 0x4000;
}
if (mode_params->src_height != mode_params->mode_height)
{
starting_height = (output_height * mode_params->src_height) / mode_params->mode_height;
vscale = (mode_params->src_height << 14) / (mode_params->mode_height - 1);
irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
}
else
{
starting_height = output_height;
vscale = 0x4000;
}
}
else
{
starting_width = mode_params->src_width;
starting_height = mode_params->src_height;
if (mode_params->src_width != mode_params->hactive)
{
hscale = (mode_params->src_width << 14) / (mode_params->hactive - 1);
irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
}
else
{
hscale = 0x4000;
}
if (mode_params->src_height != output_height)
{
vscale = (mode_params->src_height << 14) / (output_height - 1);
irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
}
else
{
vscale = 0x4000;
}
}
starting_width = (starting_width + 7) & 0xFFFF8;
if (mode_params->hactive < (starting_width >> 1) ||
output_height < (starting_height >> 1) ||
(irq_ctl && (starting_width > 1024)))
{
return CIM_STATUS_INVALIDSCALE;
}
/* VERIFY INTERLACED SCALING */
/* The output width must be less than or equal to 1024 pixels when the */
/* flicker filter is enabled. Also, scaling should be disabled when */
/* the interlacing mode is set to interlaced addressing. */
if (mode_params->flags & VG_MODEFLAG_INTERLACED)
{
if ((((mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_FLICKER) &&
(mode_params->hactive > 1024)) ||
(((mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_ADDRESS) && irq_ctl))
{
return CIM_STATUS_INVALIDSCALE;
}
}
/* CHECK FOR VALID BPP */
switch (bpp)
{
case 8: bpp_mask = DC3_DCFG_DISP_MODE_8BPP; break;
case 24: bpp_mask = DC3_DCFG_DISP_MODE_24BPP; break;
case 32: bpp_mask = DC3_DCFG_DISP_MODE_32BPP; break;
case 12: bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_12BPP; break;
case 15: bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_15BPP; break;
case 16: bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_16BPP; break;
default: return CIM_STATUS_INVALIDPARAMS;
}
vg3_bpp = bpp;
/* CLEAR PANNING OFFSETS */
vg3_delta_x = 0;
vg3_delta_y = 0;
/* SAVE PANEL PARAMETERS */
if (mode_params->flags & VG_MODEFLAG_PANELOUT)
{
vg3_panel_enable = 1;
vg3_panel_width = mode_params->panel_width;
vg3_panel_height = mode_params->panel_height;
vg3_mode_width = mode_params->mode_width;
vg3_mode_height = mode_params->mode_height;
/* INVERT THE SHIFT CLOCK IF REQUESTED */
/* Note that we avoid writing the power management register if */
/* we can help it. */
temp = READ_VID32 (DF_POWER_MANAGEMENT);
if ((mode_params->flags & VG_MODEFLAG_INVERT_SHFCLK) &&
!(temp & DF_PM_INVERT_SHFCLK))
{
WRITE_VID32 (DF_POWER_MANAGEMENT, (temp | DF_PM_INVERT_SHFCLK));
}
else if (!(mode_params->flags & VG_MODEFLAG_INVERT_SHFCLK) &&
(temp & DF_PM_INVERT_SHFCLK))
{
WRITE_VID32 (DF_POWER_MANAGEMENT, (temp & ~DF_PM_INVERT_SHFCLK));
}
/* SET PANEL TIMING VALUES */
if (!(mode_params->flags & VG_MODEFLAG_NOPANELTIMINGS))
{
unsigned long pmtim1, pmtim2, dith_ctl;
if (mode_params->flags & VG_MODEFLAG_XVGA_TFT)
{
pmtim1 = DF_DEFAULT_XVGA_PMTIM1;
pmtim2 = DF_DEFAULT_XVGA_PMTIM2;
dith_ctl = DF_DEFAULT_DITHCTL;
msr_value.low = DF_DEFAULT_XVGA_PAD_SEL_LOW;
msr_value.high = DF_DEFAULT_XVGA_PAD_SEL_HIGH;
}
else if (mode_params->flags & VG_MODEFLAG_CUSTOM_PANEL)
{
pmtim1 = mode_params->panel_tim1;
pmtim2 = mode_params->panel_tim2;
dith_ctl = mode_params->panel_dither_ctl;
msr_value.low = mode_params->panel_pad_sel_low;
msr_value.high = mode_params->panel_pad_sel_high;
}
else
{
pmtim1 = DF_DEFAULT_TFT_PMTIM1;
pmtim2 = DF_DEFAULT_TFT_PMTIM2;
dith_ctl = DF_DEFAULT_DITHCTL;
msr_value.low = DF_DEFAULT_TFT_PAD_SEL_LOW;
msr_value.high = DF_DEFAULT_TFT_PAD_SEL_HIGH;
}
WRITE_VID32 (DF_VIDEO_PANEL_TIM1, pmtim1);
WRITE_VID32 (DF_VIDEO_PANEL_TIM2, pmtim2);
WRITE_VID32 (DF_DITHER_CONTROL, dith_ctl);
msr_write64 (MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &msr_value);
}
/* SET APPROPRIATE PANEL OUTPUT MODE */
msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
msr_value.low &= ~DF_CONFIG_OUTPUT_MASK;
msr_value.low |= DF_OUTPUT_PANEL;
if (mode_params->flags & VG_MODEFLAG_CRT_AND_FP)
msr_value.low |= DF_SIMULTANEOUS_CRT_FP;
else
msr_value.low &= ~DF_SIMULTANEOUS_CRT_FP;
msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
}
else if (mode_params->flags & VG_MODEFLAG_TVOUT)
{
vg3_panel_enable = 0;
/* SET APPROPRIATE TV OUTPUT MODE */
msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
msr_value.low &= ~DF_CONFIG_OUTPUT_MASK;
msr_value.low |= DF_OUTPUT_PANEL;
if (mode_params->flags & VG_MODEFLAG_CRT_AND_FP)
msr_value.low |= DF_SIMULTANEOUS_CRT_FP;
else
msr_value.low &= ~DF_SIMULTANEOUS_CRT_FP;
msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
/* CONFIGURE PADS FOR VOP OUTPUT */
/* Note that the VOP clock is currently always inverted. */
msr_value.low = DF_DEFAULT_TV_PAD_SEL_LOW;
msr_value.high = DF_DEFAULT_TV_PAD_SEL_HIGH;
msr_write64 (MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &msr_value);
}
else
{
vg3_panel_enable = 0;
/* SET OUTPUT TO CRT ONLY */
msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
msr_value.low &= ~DF_CONFIG_OUTPUT_MASK;
msr_value.low |= DF_OUTPUT_CRT;
msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
}
/* SET UNLOCK VALUE */
unlock = READ_REG32 (DC3_UNLOCK);
WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
/*-------------------------------------------------------------------*/
/* MAKE THE SYSTEM "SAFE" */
/* Before setting a mode, we first ensure that the system is in a */
/* benign quiescent state. This involves disabling compression and */
/* all interrupt sources. It also involves terminating all accesses */
/* to memory, including video, FIFO load, VIP and the GP. */
/*-------------------------------------------------------------------*/
/* DISABLE VGA */
/* VGA *MUST* be turned off before TGEN is enabled. If not, a condition */
/* will result where VGA Enable is waiting for a VSync to be latched but */
/* a VSync will not be generated until VGA is disabled. */
temp = READ_REG32 (DC3_GENERAL_CFG) & ~DC3_GCFG_VGAE;
/* DISABLE VIDEO (INCLUDING ALPHA WINDOWS) */
WRITE_VID32 (DF_ALPHA_CONTROL_1, 0);
WRITE_VID32 (DF_ALPHA_CONTROL_1 + 32, 0);
WRITE_VID32 (DF_ALPHA_CONTROL_1 + 64, 0);
WRITE_REG32 (DC3_GENERAL_CFG, (temp & ~DC3_GCFG_VIDE));
temp = READ_VID32 (DF_VIDEO_CONFIG);
WRITE_VID32 (DF_VIDEO_CONFIG, (temp & ~DF_VCFG_VID_EN));
/* DISABLE VG INTERRUPTS */
WRITE_REG32 (DC3_IRQ, DC3_IRQ_MASK | DC3_VSYNC_IRQ_MASK |
DC3_IRQ_STATUS | DC3_VSYNC_IRQ_STATUS);
/* DISABLE GENLOCK */
genlk_ctl = READ_REG32 (DC3_GENLK_CTL);
WRITE_REG32 (DC3_GENLK_CTL, (genlk_ctl & ~DC3_GC_GENLOCK_ENABLE));
/* DISABLE VIP CAPTURE AND VIP INTERRUPTS */
WRITE_VIP32 (VIP_CONTROL1, 0);
WRITE_VIP32 (VIP_CONTROL2, 0);
WRITE_VIP32 (VIP_INTERRUPT, VIP_ALL_INTERRUPTS | (VIP_ALL_INTERRUPTS >> 16));
/* DISABLE COLOR KEYING */
/* The color key mechanism should be disabled whenever a mode switch occurs. */
temp = READ_REG32 (DC3_COLOR_KEY);
WRITE_REG32 (DC3_COLOR_KEY, (temp & ~DC3_CLR_KEY_ENABLE));
/* BLANK THE DISPLAY */
/* Note that we never blank the panel. Most flat panels have very long */
/* latency requirements when setting their power low. Some panels require */
/* upwards of 500ms before VDD goes high again. Needless to say, we are not */
/* planning to take over one half a second inside this routine. */
misc = READ_VID32 (DF_VID_MISC);
config = READ_VID32 (DF_DISPLAY_CONFIG);
WRITE_VID32 (DF_VID_MISC, (misc | DF_DAC_POWER_DOWN));
WRITE_VID32 (DF_DISPLAY_CONFIG, (config & ~(DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN)));
/* DISABLE COMPRESSION */
gcfg = READ_REG32 (DC3_GENERAL_CFG);
gcfg &= ~(DC3_GCFG_CMPE | DC3_GCFG_DECE);
WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
/* DISABLE THE TIMING GENERATOR */
dcfg = READ_REG32 (DC3_DISPLAY_CFG);
dcfg &= ~DC3_DCFG_TGEN;
WRITE_REG32 (DC3_DISPLAY_CFG, dcfg);
/* WAIT FOR PENDING MEMORY REQUESTS */
vg_delay_milliseconds(1);
/* DISABLE DISPLAY FIFO LOAD */
gcfg &= ~DC3_GCFG_DFLE;
WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
gcfg = 0;
dcfg = 0;
/* WAIT FOR THE GP TO BE IDLE (JUST IN CASE) */
while (((temp = READ_GP32 (GP3_BLT_STATUS)) & GP3_BS_BLT_BUSY) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -