⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 voyager.c

📁 嵌入式linux下sm501芯片的驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			if (++timeout == VSYNCTIMEOUT)
				break;
		}
		while (status == CMD_INTPR_STATUS_PANEL_SYNC_ACTIVE);

		/* Wait for start of vsync */
		timeout = 0;
		do
		{
			status = FIELD_GET(regRead32(CMD_INTPR_STATUS),
							   CMD_INTPR_STATUS, 
							   PANEL_SYNC);
			if (++timeout == VSYNCTIMEOUT)
				break;
		}
		while (status == CMD_INTPR_STATUS_PANEL_SYNC_INACTIVE);
	}
}


/**********************************************************************
 *
 * panelPowerSequence
 *
 * Purpose
 *    Turn the panel On/Off
 *
 * Parameters
 *    [in]
 *        on_off      - Turn panel On/Off. Can be:
 *                      PANEL_ON
 *                      PANEL_OFF
 *        vsync_delay - Number of Vsyncs to wait after each signal is
 *                      turned on/off
 *
 *    [out]
 *        None
 *
 * Returns
 *    Nothing
 *
 **********************************************************************/
static void panelPowerSequence(panel_state_t on_off, int vsync_delay)
{
	unsigned long panelControl = regRead32(PANEL_DISPLAY_CTRL);

	if (on_off == PANEL_ON)
	{
		// Turn on FPVDDEN.
		panelControl = FIELD_SET(panelControl,
								 PANEL_DISPLAY_CTRL, FPVDDEN, HIGH);
		regWrite32(PANEL_DISPLAY_CTRL, panelControl);
		panelWaitVSync(vsync_delay);

		// Turn on FPDATA.
		panelControl = FIELD_SET(panelControl, 
								 PANEL_DISPLAY_CTRL, DATA, ENABLE);
		regWrite32(PANEL_DISPLAY_CTRL, panelControl);
		panelWaitVSync(vsync_delay);

		// Turn on FPVBIAS.
		panelControl = FIELD_SET(panelControl, 
								 PANEL_DISPLAY_CTRL, VBIASEN, HIGH);
		regWrite32(PANEL_DISPLAY_CTRL, panelControl);
		panelWaitVSync(vsync_delay);

		// Turn on FPEN.
		panelControl = FIELD_SET(panelControl, 
								 PANEL_DISPLAY_CTRL, FPEN, HIGH);
		regWrite32(PANEL_DISPLAY_CTRL, panelControl);
	}

	else
	{
		// Turn off FPEN.
		panelControl = FIELD_SET(panelControl,
								 PANEL_DISPLAY_CTRL, FPEN, LOW);
		regWrite32(PANEL_DISPLAY_CTRL, panelControl);
		panelWaitVSync(vsync_delay);

		// Turn off FPVBIASEN.
		panelControl = FIELD_SET(panelControl, 
								 PANEL_DISPLAY_CTRL, VBIASEN, LOW);
		regWrite32(PANEL_DISPLAY_CTRL, panelControl);
		panelWaitVSync(vsync_delay);

		// Turn off FPDATA.
		panelControl = FIELD_SET(panelControl, 
								 PANEL_DISPLAY_CTRL, DATA, DISABLE);
		regWrite32(PANEL_DISPLAY_CTRL, panelControl);
		panelWaitVSync(vsync_delay);

		// Turn off FPVDDEN.
		panelControl = FIELD_SET(panelControl, 
								 PANEL_DISPLAY_CTRL, FPVDDEN, LOW);
		regWrite32(PANEL_DISPLAY_CTRL, panelControl);
	}
}


/**********************************************************************
 *
 * panelOn
 *
 * Purpose
 *    Turn the panel ON
 *
 * Parameters
 *    [in]
 *        nVSyncDelay - Number of Vsyncs to wait after each signal is
 *                      turned on
 *
 *    [out]
 *        None
 *
 * Returns
 *    Nothing
 *
 **********************************************************************/
void panelOn(unsigned long nVSyncDelay)
{
    panelPowerSequence(PANEL_ON, nVSyncDelay);
}


/**********************************************************************
 *
 * panelOff
 *
 * Purpose
 *    Turn the panel OFF
 *
 * Parameters
 *    [in]
 *        nVSyncDelay - Number of Vsyncs to wait after each signal is
 *                      turned off
 *
 *    [out]
 *        None
 *
 * Returns
 *    Nothing
 *
 **********************************************************************/
void panelOff(unsigned long nVSyncDelay)
{
    panelPowerSequence(PANEL_OFF, nVSyncDelay);
}


/**********************************************************************
 *
 * panelUseCRT
 *
 * Purpose
 *    Enable/disable routing of panel output to CRT monitor
 *
 * Parameters
 *    [in]
 *        bEnable - TRUE enables routing of panel output to CRT monitor
 *                  FALSE disables routing of panel output to CRT monitor
 *
 *    [out]
 *        None
 *
 * Returns
 *    Nothing
 *
 **********************************************************************/
void panelUseCRT(int bEnable)
{
    unsigned long panel_ctrl = 0;
    unsigned long crt_ctrl = 0;

    panel_ctrl = regRead32(PANEL_DISPLAY_CTRL);
    crt_ctrl = regRead32(CRT_DISPLAY_CTRL);

    if (bEnable)
	{
	    /* Enable panel graphics plane */
        panel_ctrl = FIELD_SET(panel_ctrl, PANEL_DISPLAY_CTRL, PLANE, ENABLE);

        /* Disable CRT graphics plane */
	    crt_ctrl = FIELD_SET(crt_ctrl, CRT_DISPLAY_CTRL, PLANE, DISABLE);

	    /* Route panel data to CRT monitor */
	    crt_ctrl = FIELD_SET(crt_ctrl, CRT_DISPLAY_CTRL, SELECT, PANEL);
	}
	else
	{
	    /* Disable panel graphics plane */
        panel_ctrl = FIELD_SET(panel_ctrl, PANEL_DISPLAY_CTRL, PLANE, DISABLE);

        /* Enable CRT graphics plane */
	    crt_ctrl = FIELD_SET(crt_ctrl, CRT_DISPLAY_CTRL, PLANE, ENABLE);

	    /* Do not route panel data to CRT monitor */
	    crt_ctrl = FIELD_SET(crt_ctrl, CRT_DISPLAY_CTRL, SELECT, CRT);
	}

    regWrite32(PANEL_DISPLAY_CTRL, panel_ctrl);
    regWrite32(CRT_DISPLAY_CTRL, crt_ctrl);
}

// Program new power mode.
void setPower(unsigned long nGates, unsigned long Clock)
{
	unsigned long gate_reg, clock_reg;
	unsigned long control_value;

	// Get current power mode.
	control_value = FIELD_GET(regRead32(POWER_MODE_CTRL),
							  POWER_MODE_CTRL,
							  MODE);

	switch (control_value)
	{
	case POWER_MODE_CTRL_MODE_MODE0:

		// Switch from mode 0 to mode 1.
		gate_reg = POWER_MODE1_GATE;
		clock_reg = POWER_MODE1_CLOCK;
		control_value = FIELD_SET(control_value,
					  POWER_MODE_CTRL, MODE, MODE1);
		break;

	case POWER_MODE_CTRL_MODE_MODE1:
	case POWER_MODE_CTRL_MODE_SLEEP:

		// Switch from mode 1 or sleep to mode 0.
		gate_reg = POWER_MODE0_GATE;
		clock_reg = POWER_MODE0_CLOCK;
		control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE0);
		break;

	default:
		// Invalid mode
		return;
	}

	// Program new power mode.
	regWrite32(gate_reg, nGates);
	regWrite32(clock_reg, Clock);
	regWrite32(POWER_MODE_CTRL, control_value);

	// When returning from sleep, wait until finished.
	while (FIELD_GET(regRead32(POWER_MODE_CTRL),
					 POWER_MODE_CTRL,
					 SLEEP_STATUS) == POWER_MODE_CTRL_SLEEP_STATUS_ACTIVE) ;
}

// Set DPMS state.
void setDPMS(DPMS_t state)
{
	unsigned long value;

	value = regRead32(SYSTEM_CTRL);
	switch (state)
	{
	case DPMS_ON:
		value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VPHP);
		break;

	case DPMS_STANDBY:
		value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VPHN);
		break;

	case DPMS_SUSPEND:
		value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VNHP);
		break;

	case DPMS_OFF:
		value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VNHN);
		break;
	}

	regWrite32(SYSTEM_CTRL, value);
}


// Perform a rounded division.
long roundDiv(long num, long denom)
{
	/* n / d + 1 / 2 = (2n + d) / 2d */
	return (2 * num + denom) / (2 * denom);
}

// Finds clock closest to the requested.
long findClock(long requested_clock, clock_select_t *clock, display_t display)
{
	long mclk;
	int divider, shift;
	long best_diff = 999999999;

	// Try 288MHz and 336MHz clocks.
	for (mclk = 288000000; mclk <= 336000000; mclk += 48000000)
	{
		// For CRT, try dividers 1 and 3, for panel, try divider 5 as well.
		for (divider = 1; divider <= (display == PANEL ? 5 : 3);
			 divider += 2)
		{
			// Try all 8 shift values.
			for (shift = 0; shift < 8; shift++)
			{
				// Calculate difference with requested clock.
				long diff = roundDiv(mclk, divider << shift) - requested_clock;
				if (diff < 0)
				{
					diff = -diff;
				}

				// If the difference is less than the current, use it.
				if (diff < best_diff)
				{
					// Store best difference.
					best_diff = diff;

					// Store clock values.
					clock->mclk = mclk;
					clock->divider = divider;
					clock->shift = shift;
				}
			}
		}
	}

	// Return best clock.
	return clock->mclk / (clock->divider << clock->shift);
}

// Finds the requested mode in the mode table.
mode_table_t *findMode(mode_table_t *mode_table, int width, int height,
					   int refresh_rate)
{
	// Walk the entire mode table.
	while (mode_table->pixel_clock != 0)
	{
		// If this mode matches the requested mode, return it!
		if ((mode_table->horizontal_display_end == width)
		&& (mode_table->vertical_display_end == height)
		&& (mode_table->vertical_frequency == refresh_rate))
		{
			return(mode_table);
		}

		// Next entry in the mode table.
		mode_table++;
	}

	// No mode found.
	return(NULL);
}

// Converts the VESA timing into Voyager timing.
void adjustMode(mode_table_t *vesaMode, mode_table_t *mode, display_t display)
{
	long blank_width, sync_start, sync_width;
	clock_select_t clock;

	// Calculate the VESA line and screen frequencies.
	vesaMode->horizontal_frequency = roundDiv(vesaMode->pixel_clock,
										   vesaMode->horizontal_total);
	vesaMode->vertical_frequency = roundDiv(vesaMode->horizontal_frequency,
										 vesaMode->vertical_total);

	// Calculate the sync percentages of the VESA mode.
	blank_width = vesaMode->horizontal_total
				- vesaMode->horizontal_display_end;
	sync_start = roundDiv((vesaMode->horizontal_sync_start -
					   vesaMode->horizontal_display_end) * 100, blank_width);
	sync_width = roundDiv(vesaMode->horizontal_sync_width * 100, blank_width);

	// Copy VESA mode into Voyager mode.
	*mode = *vesaMode;

	// Find the best pixel clock.
	mode->pixel_clock = findClock(vesaMode->pixel_clock * 2, &clock, display) / 2;

	// Calculate the horizontal total based on the pixel clock and VESA line
	// frequency.
	mode->horizontal_total = roundDiv(mode->pixel_clock,
								   vesaMode->horizontal_frequency);

	// Calculate the sync start and width based on the VESA percentages.
	blank_width = mode->horizontal_total - mode->horizontal_display_end;
	mode->horizontal_sync_start = mode->horizontal_display_end
								+ roundDiv(blank_width * sync_start, 100);
	mode->horizontal_sync_width = roundDiv(blank_width * sync_width, 100);

	// Calculate the line and screen frequencies.
	mode->horizontal_frequency = roundDiv(mode->pixel_clock,
									   mode->horizontal_total);
	mode->vertical_frequency = roundDiv(mode->horizontal_frequency,
									 mode->vertical_total);
}

// Fill the register structure.
void setModeRegisters(reg_table_t *register_table, mode_table_t *mode,
					  display_t display, int bpp)
{
	clock_select_t clock;
	memset(&clock, 0, sizeof(clock));

	// Calculate the clock register values.
	findClock(mode->pixel_clock * 2, &clock, display);

	if (display == PANEL)
	{
		// Set clock value for panel.
		register_table->clock
			= (clock.mclk == 288000000
				? FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_SELECT, 288)
				: FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_SELECT, 336))
			| (clock.divider == 1
				? FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_DIVIDER, 1)
				: (clock.divider == 3
					? FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_DIVIDER, 3)
					: FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_DIVIDER, 5)))
			| FIELD_VALUE(0, CURRENT_POWER_CLOCK, P2XCLK_SHIFT, clock.shift);

		// Set control register value.
		register_table->control
			= (mode->vertical_sync_polarity == POSITIVE
				? FIELD_SET(0, PANEL_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH)
				: FIELD_SET(0, PANEL_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW))
			| (mode->horizontal_sync_polarity == POSITIVE
				? FIELD_SET(0, PANEL_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH)
				: FIELD_SET(0, PANEL_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW))
			| FIELD_SET(0, PANEL_DISPLAY_CTRL, TIMING, ENABLE)
			| FIELD_SET(0, PANEL_DISPLAY_CTRL, PLANE, ENABLE)
			| (bpp == 8
				? FIELD_SET(0, PANEL_DISPLAY_CTRL, FORMAT, 8)
				: (bpp == 16
					? FIELD_SET(0, PANEL_DISPLAY_CTRL, FORMAT, 16)
					: FIELD_SET(0, PANEL_DISPLAY_CTRL, FORMAT, 32)));

		// Set timing registers.
		register_table->horizontal_total
			= FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, TOTAL,
						  mode->horizontal_total - 1)
			| FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, DISPLAY_END, 
						  mode->horizontal_display_end - 1);

		register_table->horizontal_sync
			= FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, WIDTH,
						  mode->horizontal_sync_width)
			| FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, START, 
						  mode->horizontal_sync_start - 1);

		register_table->vertical_total  
			= FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, TOTAL, 
						  mode->vertical_total - 1)
			| FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, DISPLAY_END, 
						  mode->vertical_display_end - 1);

		register_table->vertical_sync    
			= FIELD_VALUE(0, PANEL_VERTICAL_SYNC, HEIGHT, 
						  mode->vertical_sync_height)
			| FIELD_VALUE(0, PANEL_VERTICAL_SYNC, START, 
						  mode->vertical_sync_start - 1);
	}
	else
	{
		// Set clock value for CRT.
		register_table->clock
			= (clock.mclk == 288000000
				? FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_SELECT, 288)
				: FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_SELECT, 336))
			| (clock.divider == 1
				? FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_DIVIDER, 1)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -