xref: /linux/drivers/staging/sm750fb/ddk750_mode.c (revision 44f57d78)
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  */
16 static unsigned long displayControlAdjust_SM750LE(struct mode_parameter *pModeParam,
17 						  unsigned long dispControl)
18 {
19 	unsigned long x, y;
20 
21 	x = pModeParam->horizontal_display_end;
22 	y = pModeParam->vertical_display_end;
23 
24 	/*
25 	 * SM750LE has to set up the top-left and bottom-right
26 	 * registers as well.
27 	 * Note that normal SM750/SM718 only use those two register for
28 	 * auto-centering mode.
29 	 */
30 	poke32(CRT_AUTO_CENTERING_TL, 0);
31 
32 	poke32(CRT_AUTO_CENTERING_BR,
33 	       (((y - 1) << CRT_AUTO_CENTERING_BR_BOTTOM_SHIFT) &
34 		CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
35 	       ((x - 1) & CRT_AUTO_CENTERING_BR_RIGHT_MASK));
36 
37 	/*
38 	 * Assume common fields in dispControl have been properly set before
39 	 * calling this function.
40 	 * This function only sets the extra fields in dispControl.
41 	 */
42 
43 	/* Clear bit 29:27 of display control register */
44 	dispControl &= ~CRT_DISPLAY_CTRL_CLK_MASK;
45 
46 	/* Set bit 29:27 of display control register for the right clock */
47 	/* Note that SM750LE only need to supported 7 resolutions. */
48 	if (x == 800 && y == 600)
49 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL41;
50 	else if (x == 1024 && y == 768)
51 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL65;
52 	else if (x == 1152 && y == 864)
53 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80;
54 	else if (x == 1280 && y == 768)
55 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80;
56 	else if (x == 1280 && y == 720)
57 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL74;
58 	else if (x == 1280 && y == 960)
59 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108;
60 	else if (x == 1280 && y == 1024)
61 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108;
62 	else /* default to VGA clock */
63 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL25;
64 
65 	/* Set bit 25:24 of display controller */
66 	dispControl |= (CRT_DISPLAY_CTRL_CRTSELECT | CRT_DISPLAY_CTRL_RGBBIT);
67 
68 	/* Set bit 14 of display controller */
69 	dispControl |= DISPLAY_CTRL_CLOCK_PHASE;
70 
71 	poke32(CRT_DISPLAY_CTRL, dispControl);
72 
73 	return dispControl;
74 }
75 
76 /* only timing related registers will be  programed */
77 static int programModeRegisters(struct mode_parameter *pModeParam,
78 				struct pll_value *pll)
79 {
80 	int ret = 0;
81 	int cnt = 0;
82 	unsigned int tmp, reg;
83 
84 	if (pll->clockType == SECONDARY_PLL) {
85 		/* programe secondary pixel clock */
86 		poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll));
87 
88 		tmp = ((pModeParam->horizontal_total - 1) <<
89 		       CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
90 		     CRT_HORIZONTAL_TOTAL_TOTAL_MASK;
91 		tmp |= (pModeParam->horizontal_display_end - 1) &
92 		      CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK;
93 
94 		poke32(CRT_HORIZONTAL_TOTAL, tmp);
95 
96 		tmp = (pModeParam->horizontal_sync_width <<
97 		       CRT_HORIZONTAL_SYNC_WIDTH_SHIFT) &
98 		     CRT_HORIZONTAL_SYNC_WIDTH_MASK;
99 		tmp |= (pModeParam->horizontal_sync_start - 1) &
100 		      CRT_HORIZONTAL_SYNC_START_MASK;
101 
102 		poke32(CRT_HORIZONTAL_SYNC, tmp);
103 
104 		tmp = ((pModeParam->vertical_total - 1) <<
105 		       CRT_VERTICAL_TOTAL_TOTAL_SHIFT) &
106 		     CRT_VERTICAL_TOTAL_TOTAL_MASK;
107 		tmp |= (pModeParam->vertical_display_end - 1) &
108 		      CRT_VERTICAL_TOTAL_DISPLAY_END_MASK;
109 
110 		poke32(CRT_VERTICAL_TOTAL, tmp);
111 
112 		tmp = ((pModeParam->vertical_sync_height <<
113 		       CRT_VERTICAL_SYNC_HEIGHT_SHIFT)) &
114 		     CRT_VERTICAL_SYNC_HEIGHT_MASK;
115 		tmp |= (pModeParam->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 (pModeParam->vertical_sync_polarity)
122 			tmp |= DISPLAY_CTRL_VSYNC_PHASE;
123 		if (pModeParam->horizontal_sync_polarity)
124 			tmp |= DISPLAY_CTRL_HSYNC_PHASE;
125 
126 		if (sm750_get_chip_type() == SM750LE) {
127 			displayControlAdjust_SM750LE(pModeParam, 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->clockType == PRIMARY_PLL) {
138 		unsigned int reserved;
139 
140 		poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll));
141 
142 		reg = ((pModeParam->horizontal_total - 1) <<
143 			PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
144 			PANEL_HORIZONTAL_TOTAL_TOTAL_MASK;
145 		reg |= ((pModeParam->horizontal_display_end - 1) &
146 			PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK);
147 		poke32(PANEL_HORIZONTAL_TOTAL, reg);
148 
149 		poke32(PANEL_HORIZONTAL_SYNC,
150 		       ((pModeParam->horizontal_sync_width <<
151 			 PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT) &
152 			PANEL_HORIZONTAL_SYNC_WIDTH_MASK) |
153 		       ((pModeParam->horizontal_sync_start - 1) &
154 			PANEL_HORIZONTAL_SYNC_START_MASK));
155 
156 		poke32(PANEL_VERTICAL_TOTAL,
157 		       (((pModeParam->vertical_total - 1) <<
158 			 PANEL_VERTICAL_TOTAL_TOTAL_SHIFT) &
159 			PANEL_VERTICAL_TOTAL_TOTAL_MASK) |
160 		       ((pModeParam->vertical_display_end - 1) &
161 			PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK));
162 
163 		poke32(PANEL_VERTICAL_SYNC,
164 		       ((pModeParam->vertical_sync_height <<
165 			 PANEL_VERTICAL_SYNC_HEIGHT_SHIFT) &
166 			PANEL_VERTICAL_SYNC_HEIGHT_MASK) |
167 		       ((pModeParam->vertical_sync_start - 1) &
168 			PANEL_VERTICAL_SYNC_START_MASK));
169 
170 		tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
171 		if (pModeParam->vertical_sync_polarity)
172 			tmp |= DISPLAY_CTRL_VSYNC_PHASE;
173 		if (pModeParam->horizontal_sync_polarity)
174 			tmp |= DISPLAY_CTRL_HSYNC_PHASE;
175 		if (pModeParam->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 	} else {
204 		ret = -1;
205 	}
206 	return ret;
207 }
208 
209 int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock)
210 {
211 	struct pll_value pll;
212 	unsigned int uiActualPixelClk;
213 
214 	pll.inputFreq = DEFAULT_INPUT_CLOCK;
215 	pll.clockType = clock;
216 
217 	uiActualPixelClk = sm750_calc_pll_value(parm->pixel_clock, &pll);
218 	if (sm750_get_chip_type() == SM750LE) {
219 		/* set graphic mode via IO method */
220 		outb_p(0x88, 0x3d4);
221 		outb_p(0x06, 0x3d5);
222 	}
223 	programModeRegisters(parm, &pll);
224 	return 0;
225 }
226