Contributors: 14
Author Tokens Token Proportion Commits Commit Proportion
Sudip Mukherjee 452 55.32% 1 3.03%
Mike Rapoport 238 29.13% 14 42.42%
Dorcas AnonoLitunya 47 5.75% 6 18.18%
Arushi Singhal 40 4.90% 2 6.06%
Matthieu Simon 19 2.33% 1 3.03%
Mihaela Muraru 4 0.49% 1 3.03%
Ido Tamir 4 0.49% 1 3.03%
Arnd Bergmann 3 0.37% 1 3.03%
Eric S. Stone 3 0.37% 1 3.03%
Moshe Green 2 0.24% 1 3.03%
Christian Lütke-Stetzkamp 2 0.24% 1 3.03%
Matej Vasek 1 0.12% 1 3.03%
Greg Kroah-Hartman 1 0.12% 1 3.03%
Phil Turnbull 1 0.12% 1 3.03%
Total 817 33


// SPDX-License-Identifier: GPL-2.0

#include "ddk750_reg.h"
#include "ddk750_mode.h"
#include "ddk750_chip.h"

/*
 * SM750LE only:
 * This function takes care extra registers and bit fields required to set
 * up a mode in SM750LE
 *
 * Explanation about Display Control register:
 * HW only supports 7 predefined pixel clocks, and clock select is
 * in bit 29:27 of Display Control register.
 */
static unsigned long
display_control_adjust_SM750LE(struct mode_parameter *mode_param,
			       unsigned long disp_control)
{
	unsigned long x, y;

	x = mode_param->horizontal_display_end;
	y = mode_param->vertical_display_end;

	/*
	 * SM750LE has to set up the top-left and bottom-right
	 * registers as well.
	 * Note that normal SM750/SM718 only use those two register for
	 * auto-centering mode.
	 */
	poke32(CRT_AUTO_CENTERING_TL, 0);

	poke32(CRT_AUTO_CENTERING_BR,
	       (((y - 1) << CRT_AUTO_CENTERING_BR_BOTTOM_SHIFT) &
		CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
	       ((x - 1) & CRT_AUTO_CENTERING_BR_RIGHT_MASK));

	/*
	 * Assume common fields in disp_control have been properly set before
	 * calling this function.
	 * This function only sets the extra fields in disp_control.
	 */

	/* Clear bit 29:27 of display control register */
	disp_control &= ~CRT_DISPLAY_CTRL_CLK_MASK;

	/* Set bit 29:27 of display control register for the right clock */
	/* Note that SM750LE only need to supported 7 resolutions. */
	if (x == 800 && y == 600)
		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL41;
	else if (x == 1024 && y == 768)
		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL65;
	else if (x == 1152 && y == 864)
		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL80;
	else if (x == 1280 && y == 768)
		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL80;
	else if (x == 1280 && y == 720)
		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL74;
	else if (x == 1280 && y == 960)
		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL108;
	else if (x == 1280 && y == 1024)
		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL108;
	else /* default to VGA clock */
		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL25;

	/* Set bit 25:24 of display controller */
	disp_control |= (CRT_DISPLAY_CTRL_CRTSELECT | CRT_DISPLAY_CTRL_RGBBIT);

	/* Set bit 14 of display controller */
	disp_control |= DISPLAY_CTRL_CLOCK_PHASE;

	poke32(CRT_DISPLAY_CTRL, disp_control);

	return disp_control;
}

/* only timing related registers will be  programed */
static void program_mode_registers(struct mode_parameter *mode_param,
				   struct pll_value *pll)
{
	int cnt = 0;
	unsigned int tmp, reg;

	if (pll->clock_type == SECONDARY_PLL) {
		/* programe secondary pixel clock */
		poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll));

		tmp = ((mode_param->horizontal_total - 1) <<
		       CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
		     CRT_HORIZONTAL_TOTAL_TOTAL_MASK;
		tmp |= (mode_param->horizontal_display_end - 1) &
		      CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK;

		poke32(CRT_HORIZONTAL_TOTAL, tmp);

		tmp = (mode_param->horizontal_sync_width <<
		       CRT_HORIZONTAL_SYNC_WIDTH_SHIFT) &
		     CRT_HORIZONTAL_SYNC_WIDTH_MASK;
		tmp |= (mode_param->horizontal_sync_start - 1) &
		      CRT_HORIZONTAL_SYNC_START_MASK;

		poke32(CRT_HORIZONTAL_SYNC, tmp);

		tmp = ((mode_param->vertical_total - 1) <<
		       CRT_VERTICAL_TOTAL_TOTAL_SHIFT) &
		     CRT_VERTICAL_TOTAL_TOTAL_MASK;
		tmp |= (mode_param->vertical_display_end - 1) &
		      CRT_VERTICAL_TOTAL_DISPLAY_END_MASK;

		poke32(CRT_VERTICAL_TOTAL, tmp);

		tmp = ((mode_param->vertical_sync_height <<
		       CRT_VERTICAL_SYNC_HEIGHT_SHIFT)) &
		     CRT_VERTICAL_SYNC_HEIGHT_MASK;
		tmp |= (mode_param->vertical_sync_start - 1) &
		      CRT_VERTICAL_SYNC_START_MASK;

		poke32(CRT_VERTICAL_SYNC, tmp);

		tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
		if (mode_param->vertical_sync_polarity)
			tmp |= DISPLAY_CTRL_VSYNC_PHASE;
		if (mode_param->horizontal_sync_polarity)
			tmp |= DISPLAY_CTRL_HSYNC_PHASE;

		if (sm750_get_chip_type() == SM750LE) {
			display_control_adjust_SM750LE(mode_param, tmp);
		} else {
			reg = peek32(CRT_DISPLAY_CTRL) &
				~(DISPLAY_CTRL_VSYNC_PHASE |
				  DISPLAY_CTRL_HSYNC_PHASE |
				  DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE);

			poke32(CRT_DISPLAY_CTRL, tmp | reg);
		}

	} else if (pll->clock_type == PRIMARY_PLL) {
		unsigned int reserved;

		poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll));

		reg = ((mode_param->horizontal_total - 1) <<
			PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
			PANEL_HORIZONTAL_TOTAL_TOTAL_MASK;
		reg |= ((mode_param->horizontal_display_end - 1) &
			PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK);
		poke32(PANEL_HORIZONTAL_TOTAL, reg);

		poke32(PANEL_HORIZONTAL_SYNC,
		       ((mode_param->horizontal_sync_width <<
			 PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT) &
			PANEL_HORIZONTAL_SYNC_WIDTH_MASK) |
		       ((mode_param->horizontal_sync_start - 1) &
			PANEL_HORIZONTAL_SYNC_START_MASK));

		poke32(PANEL_VERTICAL_TOTAL,
		       (((mode_param->vertical_total - 1) <<
			 PANEL_VERTICAL_TOTAL_TOTAL_SHIFT) &
			PANEL_VERTICAL_TOTAL_TOTAL_MASK) |
		       ((mode_param->vertical_display_end - 1) &
			PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK));

		poke32(PANEL_VERTICAL_SYNC,
		       ((mode_param->vertical_sync_height <<
			 PANEL_VERTICAL_SYNC_HEIGHT_SHIFT) &
			PANEL_VERTICAL_SYNC_HEIGHT_MASK) |
		       ((mode_param->vertical_sync_start - 1) &
			PANEL_VERTICAL_SYNC_START_MASK));

		tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
		if (mode_param->vertical_sync_polarity)
			tmp |= DISPLAY_CTRL_VSYNC_PHASE;
		if (mode_param->horizontal_sync_polarity)
			tmp |= DISPLAY_CTRL_HSYNC_PHASE;
		if (mode_param->clock_phase_polarity)
			tmp |= DISPLAY_CTRL_CLOCK_PHASE;

		reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK |
			PANEL_DISPLAY_CTRL_VSYNC;

		reg = (peek32(PANEL_DISPLAY_CTRL) & ~reserved) &
			~(DISPLAY_CTRL_CLOCK_PHASE | DISPLAY_CTRL_VSYNC_PHASE |
			  DISPLAY_CTRL_HSYNC_PHASE | DISPLAY_CTRL_TIMING |
			  DISPLAY_CTRL_PLANE);

		/*
		 * May a hardware bug or just my test chip (not confirmed).
		 * PANEL_DISPLAY_CTRL register seems requiring few writes
		 * before a value can be successfully written in.
		 * Added some masks to mask out the reserved bits.
		 * Note: This problem happens by design. The hardware will wait
		 *       for the next vertical sync to turn on/off the plane.
		 */
		poke32(PANEL_DISPLAY_CTRL, tmp | reg);

		while ((peek32(PANEL_DISPLAY_CTRL) & ~reserved) !=
			(tmp | reg)) {
			cnt++;
			if (cnt > 1000)
				break;
			poke32(PANEL_DISPLAY_CTRL, tmp | reg);
		}
	}
}

int ddk750_set_mode_timing(struct mode_parameter *parm, enum clock_type clock)
{
	struct pll_value pll;

	pll.input_freq = DEFAULT_INPUT_CLOCK;
	pll.clock_type = clock;

	sm750_calc_pll_value(parm->pixel_clock, &pll);
	if (sm750_get_chip_type() == SM750LE) {
		/* set graphic mode via IO method */
		outb_p(0x88, 0x3d4);
		outb_p(0x06, 0x3d5);
	}
	program_mode_registers(parm, &pll);
	return 0;
}