1// SPDX-License-Identifier: GPL-2.0
2
3#include "ddk750_reg.h"
4#include "ddk750_mode.h"
5#include "ddk750_chip.h"
6
7/*
8 * SM750LE only:
9 * This function takes care extra registers and bit fields required to set
10 * up a mode in SM750LE
11 *
12 * Explanation about Display Control register:
13 * HW only supports 7 predefined pixel clocks, and clock select is
14 * in bit 29:27 of Display Control register.
15 */
16static unsigned long
17display_control_adjust_SM750LE(struct mode_parameter *mode_param,
18			       unsigned long disp_control)
19{
20	unsigned long x, y;
21
22	x = mode_param->horizontal_display_end;
23	y = mode_param->vertical_display_end;
24
25	/*
26	 * SM750LE has to set up the top-left and bottom-right
27	 * registers as well.
28	 * Note that normal SM750/SM718 only use those two register for
29	 * auto-centering mode.
30	 */
31	poke32(CRT_AUTO_CENTERING_TL, 0);
32
33	poke32(CRT_AUTO_CENTERING_BR,
34	       (((y - 1) << CRT_AUTO_CENTERING_BR_BOTTOM_SHIFT) &
35		CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
36	       ((x - 1) & CRT_AUTO_CENTERING_BR_RIGHT_MASK));
37
38	/*
39	 * Assume common fields in disp_control have been properly set before
40	 * calling this function.
41	 * This function only sets the extra fields in disp_control.
42	 */
43
44	/* Clear bit 29:27 of display control register */
45	disp_control &= ~CRT_DISPLAY_CTRL_CLK_MASK;
46
47	/* Set bit 29:27 of display control register for the right clock */
48	/* Note that SM750LE only need to supported 7 resolutions. */
49	if (x == 800 && y == 600)
50		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL41;
51	else if (x == 1024 && y == 768)
52		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL65;
53	else if (x == 1152 && y == 864)
54		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL80;
55	else if (x == 1280 && y == 768)
56		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL80;
57	else if (x == 1280 && y == 720)
58		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL74;
59	else if (x == 1280 && y == 960)
60		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL108;
61	else if (x == 1280 && y == 1024)
62		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL108;
63	else /* default to VGA clock */
64		disp_control |= CRT_DISPLAY_CTRL_CLK_PLL25;
65
66	/* Set bit 25:24 of display controller */
67	disp_control |= (CRT_DISPLAY_CTRL_CRTSELECT | CRT_DISPLAY_CTRL_RGBBIT);
68
69	/* Set bit 14 of display controller */
70	disp_control |= DISPLAY_CTRL_CLOCK_PHASE;
71
72	poke32(CRT_DISPLAY_CTRL, disp_control);
73
74	return disp_control;
75}
76
77/* only timing related registers will be  programed */
78static void program_mode_registers(struct mode_parameter *mode_param,
79				   struct pll_value *pll)
80{
81	int cnt = 0;
82	unsigned int tmp, reg;
83
84	if (pll->clock_type == SECONDARY_PLL) {
85		/* programe secondary pixel clock */
86		poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll));
87
88		tmp = ((mode_param->horizontal_total - 1) <<
89		       CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
90		     CRT_HORIZONTAL_TOTAL_TOTAL_MASK;
91		tmp |= (mode_param->horizontal_display_end - 1) &
92		      CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK;
93
94		poke32(CRT_HORIZONTAL_TOTAL, tmp);
95
96		tmp = (mode_param->horizontal_sync_width <<
97		       CRT_HORIZONTAL_SYNC_WIDTH_SHIFT) &
98		     CRT_HORIZONTAL_SYNC_WIDTH_MASK;
99		tmp |= (mode_param->horizontal_sync_start - 1) &
100		      CRT_HORIZONTAL_SYNC_START_MASK;
101
102		poke32(CRT_HORIZONTAL_SYNC, tmp);
103
104		tmp = ((mode_param->vertical_total - 1) <<
105		       CRT_VERTICAL_TOTAL_TOTAL_SHIFT) &
106		     CRT_VERTICAL_TOTAL_TOTAL_MASK;
107		tmp |= (mode_param->vertical_display_end - 1) &
108		      CRT_VERTICAL_TOTAL_DISPLAY_END_MASK;
109
110		poke32(CRT_VERTICAL_TOTAL, tmp);
111
112		tmp = ((mode_param->vertical_sync_height <<
113		       CRT_VERTICAL_SYNC_HEIGHT_SHIFT)) &
114		     CRT_VERTICAL_SYNC_HEIGHT_MASK;
115		tmp |= (mode_param->vertical_sync_start - 1) &
116		      CRT_VERTICAL_SYNC_START_MASK;
117
118		poke32(CRT_VERTICAL_SYNC, tmp);
119
120		tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
121		if (mode_param->vertical_sync_polarity)
122			tmp |= DISPLAY_CTRL_VSYNC_PHASE;
123		if (mode_param->horizontal_sync_polarity)
124			tmp |= DISPLAY_CTRL_HSYNC_PHASE;
125
126		if (sm750_get_chip_type() == SM750LE) {
127			display_control_adjust_SM750LE(mode_param, tmp);
128		} else {
129			reg = peek32(CRT_DISPLAY_CTRL) &
130				~(DISPLAY_CTRL_VSYNC_PHASE |
131				  DISPLAY_CTRL_HSYNC_PHASE |
132				  DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE);
133
134			poke32(CRT_DISPLAY_CTRL, tmp | reg);
135		}
136
137	} else if (pll->clock_type == PRIMARY_PLL) {
138		unsigned int reserved;
139
140		poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll));
141
142		reg = ((mode_param->horizontal_total - 1) <<
143			PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
144			PANEL_HORIZONTAL_TOTAL_TOTAL_MASK;
145		reg |= ((mode_param->horizontal_display_end - 1) &
146			PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK);
147		poke32(PANEL_HORIZONTAL_TOTAL, reg);
148
149		poke32(PANEL_HORIZONTAL_SYNC,
150		       ((mode_param->horizontal_sync_width <<
151			 PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT) &
152			PANEL_HORIZONTAL_SYNC_WIDTH_MASK) |
153		       ((mode_param->horizontal_sync_start - 1) &
154			PANEL_HORIZONTAL_SYNC_START_MASK));
155
156		poke32(PANEL_VERTICAL_TOTAL,
157		       (((mode_param->vertical_total - 1) <<
158			 PANEL_VERTICAL_TOTAL_TOTAL_SHIFT) &
159			PANEL_VERTICAL_TOTAL_TOTAL_MASK) |
160		       ((mode_param->vertical_display_end - 1) &
161			PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK));
162
163		poke32(PANEL_VERTICAL_SYNC,
164		       ((mode_param->vertical_sync_height <<
165			 PANEL_VERTICAL_SYNC_HEIGHT_SHIFT) &
166			PANEL_VERTICAL_SYNC_HEIGHT_MASK) |
167		       ((mode_param->vertical_sync_start - 1) &
168			PANEL_VERTICAL_SYNC_START_MASK));
169
170		tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
171		if (mode_param->vertical_sync_polarity)
172			tmp |= DISPLAY_CTRL_VSYNC_PHASE;
173		if (mode_param->horizontal_sync_polarity)
174			tmp |= DISPLAY_CTRL_HSYNC_PHASE;
175		if (mode_param->clock_phase_polarity)
176			tmp |= DISPLAY_CTRL_CLOCK_PHASE;
177
178		reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK |
179			PANEL_DISPLAY_CTRL_VSYNC;
180
181		reg = (peek32(PANEL_DISPLAY_CTRL) & ~reserved) &
182			~(DISPLAY_CTRL_CLOCK_PHASE | DISPLAY_CTRL_VSYNC_PHASE |
183			  DISPLAY_CTRL_HSYNC_PHASE | DISPLAY_CTRL_TIMING |
184			  DISPLAY_CTRL_PLANE);
185
186		/*
187		 * May a hardware bug or just my test chip (not confirmed).
188		 * PANEL_DISPLAY_CTRL register seems requiring few writes
189		 * before a value can be successfully written in.
190		 * Added some masks to mask out the reserved bits.
191		 * Note: This problem happens by design. The hardware will wait
192		 *       for the next vertical sync to turn on/off the plane.
193		 */
194		poke32(PANEL_DISPLAY_CTRL, tmp | reg);
195
196		while ((peek32(PANEL_DISPLAY_CTRL) & ~reserved) !=
197			(tmp | reg)) {
198			cnt++;
199			if (cnt > 1000)
200				break;
201			poke32(PANEL_DISPLAY_CTRL, tmp | reg);
202		}
203	}
204}
205
206int ddk750_set_mode_timing(struct mode_parameter *parm, enum clock_type clock)
207{
208	struct pll_value pll;
209
210	pll.input_freq = DEFAULT_INPUT_CLOCK;
211	pll.clock_type = clock;
212
213	sm750_calc_pll_value(parm->pixel_clock, &pll);
214	if (sm750_get_chip_type() == SM750LE) {
215		/* set graphic mode via IO method */
216		outb_p(0x88, 0x3d4);
217		outb_p(0x06, 0x3d5);
218	}
219	program_mode_registers(parm, &pll);
220	return 0;
221}
222