📄 cim_vg.c
字号:
/* We assume the input frequency is 48 MHz, which is represented */
/* in 16.16 fixed point as 0x300000. The PLL calculation is: */
/* n + 1 */
/* Fout = 48.000 * -------------- */
/* m + 1 * p + 1 */
p = msr_value.high & 0xF;
n = (msr_value.high >> 4) & 0xFF;
m = (msr_value.high >> 12) & 0x7;
current_display->frequency = (0x300000 * (n + 1)) / ((p + 1) * (m + 1));
return CIM_STATUS_INEXACTMATCH;
}
current_display->frequency = CimarronPLLFrequencies[i].frequency;
/* NOW SEARCH FOR AN IDENTICAL MODE */
/* This is just to inform the user that an exact match was found. */
/* With an exact match, the user can use the refresh rate flag that */
/* is returned in the VG_DISPLAY_MODE structure. */
for (i = 0; i < NUM_CIMARRON_DISPLAY_MODES; i++)
{
if ((CimarronDisplayModes[i].flags & current_display->flags) &&
CimarronDisplayModes[i].frequency == current_display->frequency &&
CimarronDisplayModes[i].hactive == current_display->hactive &&
CimarronDisplayModes[i].hblankstart == current_display->hblankstart &&
CimarronDisplayModes[i].hsyncstart == current_display->hsyncstart &&
CimarronDisplayModes[i].hsyncend == current_display->hsyncend &&
CimarronDisplayModes[i].hblankend == current_display->hblankend &&
CimarronDisplayModes[i].htotal == current_display->htotal &&
CimarronDisplayModes[i].vactive == current_display->vactive &&
CimarronDisplayModes[i].vblankstart == current_display->vblankstart &&
CimarronDisplayModes[i].vsyncstart == current_display->vsyncstart &&
CimarronDisplayModes[i].vsyncend == current_display->vsyncend &&
CimarronDisplayModes[i].vblankend == current_display->vblankend &&
CimarronDisplayModes[i].vtotal == current_display->vtotal)
{
break;
}
}
if (i == NUM_CIMARRON_DISPLAY_MODES)
return CIM_STATUS_INEXACTMATCH;
current_display->internal_flags |= (CimarronDisplayModes[i].internal_flags & VG_SUPPORTFLAG_HZMASK);
return CIM_STATUS_OK;
}
/*---------------------------------------------------------------------------
* vg_set_scaler_filter_coefficients
*
* This routine sets the vertical and horizontal filter coefficients for
* graphics scaling. If either of the input arrays is specified as NULL, a
* set of default coeffecients will be used.
*---------------------------------------------------------------------------*/
int vg_set_scaler_filter_coefficients (long h_taps[][5], long v_taps[][3])
{
unsigned long irqfilt, i;
unsigned long temp0, temp1;
unsigned long lock;
/* ENABLE ACCESS TO THE HORIZONTAL COEFFICIENTS */
irqfilt = READ_REG32 (DC3_IRQ_FILT_CTL);
irqfilt |= DC3_IRQFILT_H_FILT_SEL;
/* UNLOCK THE COEFFICIENT REGISTERS */
lock = READ_REG32 (DC3_UNLOCK);
WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
/* WRITE COEFFICIENTS */
/* Coefficient indexes do not auto-increment, so we must */
/* write the address for every phase */
for (i = 0; i < 256; i++)
{
WRITE_REG32 (DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
if (!h_taps)
{
temp0 = CimarronHorizontalGraphicsFilter[i][0];
temp1 = CimarronHorizontalGraphicsFilter[i][1];
}
else
{
temp0 = ((unsigned long)h_taps[i][0] & 0x3FF) |
(((unsigned long)h_taps[i][1] & 0x3FF) << 10) |
(((unsigned long)h_taps[i][2] & 0x3FF) << 20);
temp1 = ((unsigned long)h_taps[i][3] & 0x3FF) |
(((unsigned long)h_taps[i][4] & 0x3FF) << 10);
}
WRITE_REG32 (DC3_FILT_COEFF1, temp0);
WRITE_REG32 (DC3_FILT_COEFF2, temp1);
}
/* ENABLE ACCESS TO THE VERTICAL COEFFICIENTS */
irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
/* WRITE COEFFICIENTS */
for (i = 0; i < 256; i++)
{
WRITE_REG32 (DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
if (!v_taps)
{
temp0 = CimarronVerticalGraphicsFilter[i];
}
else
{
temp0 = ((unsigned long)v_taps[i][0] & 0x3FF) |
(((unsigned long)v_taps[i][1] & 0x3FF) << 10) |
(((unsigned long)v_taps[i][2] & 0x3FF) << 20);
}
WRITE_REG32 (DC3_FILT_COEFF1, temp0);
}
WRITE_REG32 (DC3_UNLOCK, lock);
return CIM_STATUS_OK;
}
/*---------------------------------------------------------------------------
* vg_configure_flicker_filter
*
* This routine updates the VG flicker filter settings when in an interlaced
* mode. Note that flicker filtering is enabled inside a mode set. This routine
* is provided to change from the default flicker filter setting of
* 1/4, 1/2, 1/4.
*---------------------------------------------------------------------------*/
int vg_configure_flicker_filter (unsigned long flicker_strength, int flicker_alpha)
{
unsigned long unlock;
unsigned long genlk_ctl;
/* CHECK FOR VALID FLICKER SETTING */
if (flicker_strength != VG_FLICKER_FILTER_NONE &&
flicker_strength != VG_FLICKER_FILTER_1_16 &&
flicker_strength != VG_FLICKER_FILTER_1_8 &&
flicker_strength != VG_FLICKER_FILTER_1_4 &&
flicker_strength != VG_FLICKER_FILTER_5_16)
{
return CIM_STATUS_INVALIDPARAMS;
}
unlock = READ_REG32 (DC3_UNLOCK);
genlk_ctl = READ_REG32 (DC3_GENLK_CTL) & ~(DC3_GC_FLICKER_FILTER_MASK | DC3_GC_ALPHA_FLICK_ENABLE);
genlk_ctl |= flicker_strength;
if (flicker_alpha)
genlk_ctl |= DC3_GC_ALPHA_FLICK_ENABLE;
WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
WRITE_REG32 (DC3_GENLK_CTL, genlk_ctl);
WRITE_REG32 (DC3_UNLOCK, unlock);
return CIM_STATUS_OK;
}
/*---------------------------------------------------------------------------
* vg_set_clock_frequency
*
* This routine sets the frequency of the dot clock. The input to this routine
* is a 16.16 fraction. If an exact match is not found, this routine will program
* the closest available frequency and return CIM_STATUS_INEXACTMATCH.
*---------------------------------------------------------------------------*/
int vg_set_clock_frequency (unsigned long frequency, unsigned long pll_flags)
{
Q_WORD msr_value;
unsigned long timeout;
unsigned long index = 0;
unsigned long unlock, i;
unsigned long pll_high, pll_low;
long diff, min = 0;
/* FIND THE REGISTER VALUES FOR THE DESIRED FREQUENCY */
/* Search the table for the closest frequency (16.16 format). */
/* This search is skipped if the user is manually specifying */
/* the MSR value. */
pll_low = 0;
if (!(pll_flags & VG_PLL_MANUAL))
{
min = (long)CimarronPLLFrequencies[0].frequency - (long)frequency;
if (min < 0L)
min = -min;
for (i = 1; i < NUM_CIMARRON_PLL_FREQUENCIES; i++)
{
diff = (long)CimarronPLLFrequencies[i].frequency - (long)frequency;
if (diff < 0L)
diff = -diff;
if (diff < min)
{
min = diff;
index = i;
}
}
pll_high = CimarronPLLFrequencies[index].pll_value & 0x00007FFF;
}
else
{
pll_high = frequency;
}
if (pll_flags & VG_PLL_DIVIDE_BY_2)
pll_low |= GLCP_DOTPLL_HALFPIX;
if (pll_flags & VG_PLL_DIVIDE_BY_4)
pll_high |= GLCP_DOTPLL_DIV4;
if (pll_flags & VG_PLL_BYPASS)
pll_low |= GLCP_DOTPLL_BYPASS;
if (pll_flags & VG_PLL_VIP_CLOCK)
pll_high |= GLCP_DOTPLL_VIPCLK;
/* VERIFY THAT WE ARE NOT WRITING WHAT IS ALREADY IN THE REGISTERS */
/* The Dot PLL reset bit is tied to VDD for flat panels. This can */
/* cause a brief drop in flat panel power, which can cause serious */
/* glitches on some panels. */
msr_read64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
if ((msr_value.low & GLCP_DOTPLL_LOCK) &&
((msr_value.low & (GLCP_DOTPLL_HALFPIX | GLCP_DOTPLL_BYPASS)) == pll_low) &&
(msr_value.high == pll_high))
{
return CIM_STATUS_OK;
}
/* PROGRAM THE SETTINGS WITH THE RESET BIT SET */
/* Clear the bypass bit to ensure that the programmed */
/* M, N and P values are being used. */
msr_value.high = pll_high;
msr_value.low &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX);
msr_value.low |= (pll_low | 0x00000001);
msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
/* WAIT FOR THE LOCK BIT */
/* The PLL spec states that the PLL may take up to 100 us to */
/* properly lock. Furthermore, the lock signal is not 100% */
/* reliable. To address this, we add a hefty delay followed */
/* by a polling loop that times out after a 1000 reads. */
unlock = READ_REG32 (DC3_UNLOCK);
for (timeout = 0; timeout < 1280; timeout++)
WRITE_REG32 (DC3_UNLOCK, unlock);
for (timeout = 0; timeout < 1000; timeout++)
{
msr_read64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
if (msr_value.low & GLCP_DOTPLL_LOCK)
break;
}
/* CLEAR THE RESET BIT */
msr_value.low &= 0xFFFFFFFE;
msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
/* DID THE PLL SUCCESSFULLY LOCK? */
if (!(msr_value.low & GLCP_DOTPLL_LOCK))
return CIM_STATUS_NOLOCK;
/* RETURN THE APPROPRIATE CODE */
if (min == 0)
return CIM_STATUS_OK;
else
return CIM_STATUS_INEXACTMATCH;
}
/*---------------------------------------------------------------------------
* vg_set_border_color
*
* This routine sets the color used as the border in centered panel modes.
*---------------------------------------------------------------------------*/
int vg_set_border_color (unsigned long border_color)
{
unsigned long lock = READ_REG32 (DC3_UNLOCK);
WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
WRITE_REG32 (DC3_PAL_ADDRESS, 0x104);
WRITE_REG32 (DC3_PAL_DATA, border_color);
WRITE_REG32 (DC3_UNLOCK, lock);
return CIM_STATUS_OK;
}
/*---------------------------------------------------------------------------
* vg_set_cursor_enable
*
* This routine enables or disables the hardware cursor. This routine should
* only be called after the hardware cursor has been completely configured.
*---------------------------------------------------------------------------*/
int vg_set_cursor_enable(int enable)
{
unsigned long unlock, gcfg;
/* SET OR CLEAR CURSOR ENABLE BIT */
unlock = READ_REG32(DC3_UNLOCK);
gcfg = READ_REG32(DC3_GENERAL_CFG);
if (enable) gcfg |= DC3_GCFG_CURE;
else gcfg &= ~(DC3_GCFG_CURE);
/* WRITE NEW REGISTER VALUE */
WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
WRITE_REG32 (DC3_UNLOCK, unlock);
return CIM_STATUS_OK;
}
/*---------------------------------------------------------------------------
* vg_set_mono_cursor_colors
*
* This routine sets the colors of the hardware monochrome cursor.
*---------------------------------------------------------------------------*/
int vg_set_mono_cursor_colors (unsigned long bkcolor, unsigned long fgcolor)
{
unsigned long lock = READ_REG32 (DC3_UNLOCK);
/* SET CURSOR COLORS */
WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
WRITE_REG32 (DC3_PAL_ADDRESS, 0x100);
WRITE_REG32 (DC3_PAL_DATA, bkcolor);
WRITE_REG32 (DC3_PAL_DATA, fgcolor);
WRITE_REG32 (DC3_UNLOCK, lock);
return CIM_STATUS_OK;
}
/*---------------------------------------------------------------------------
* vg_set_cursor_position
*
* This routine sets the position of the hardware cursor. The cursor hotspots
* and memory offset must have been specified in an earlier call to
* a vg_set_cursor_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -