xref: /linux/drivers/staging/sm750fb/ddk750_mode.c (revision 9a6b55ac)
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
17 displayControlAdjust_SM750LE(struct mode_parameter *pModeParam,
18 			     unsigned long dispControl)
19 {
20 	unsigned long x, y;
21 
22 	x = pModeParam->horizontal_display_end;
23 	y = pModeParam->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 dispControl have been properly set before
40 	 * calling this function.
41 	 * This function only sets the extra fields in dispControl.
42 	 */
43 
44 	/* Clear bit 29:27 of display control register */
45 	dispControl &= ~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 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL41;
51 	else if (x == 1024 && y == 768)
52 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL65;
53 	else if (x == 1152 && y == 864)
54 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80;
55 	else if (x == 1280 && y == 768)
56 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80;
57 	else if (x == 1280 && y == 720)
58 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL74;
59 	else if (x == 1280 && y == 960)
60 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108;
61 	else if (x == 1280 && y == 1024)
62 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108;
63 	else /* default to VGA clock */
64 		dispControl |= CRT_DISPLAY_CTRL_CLK_PLL25;
65 
66 	/* Set bit 25:24 of display controller */
67 	dispControl |= (CRT_DISPLAY_CTRL_CRTSELECT | CRT_DISPLAY_CTRL_RGBBIT);
68 
69 	/* Set bit 14 of display controller */
70 	dispControl |= DISPLAY_CTRL_CLOCK_PHASE;
71 
72 	poke32(CRT_DISPLAY_CTRL, dispControl);
73 
74 	return dispControl;
75 }
76 
77 /* only timing related registers will be  programed */
78 static int programModeRegisters(struct mode_parameter *pModeParam,
79 				struct pll_value *pll)
80 {
81 	int ret = 0;
82 	int cnt = 0;
83 	unsigned int tmp, reg;
84 
85 	if (pll->clock_type == SECONDARY_PLL) {
86 		/* programe secondary pixel clock */
87 		poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll));
88 
89 		tmp = ((pModeParam->horizontal_total - 1) <<
90 		       CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
91 		     CRT_HORIZONTAL_TOTAL_TOTAL_MASK;
92 		tmp |= (pModeParam->horizontal_display_end - 1) &
93 		      CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK;
94 
95 		poke32(CRT_HORIZONTAL_TOTAL, tmp);
96 
97 		tmp = (pModeParam->horizontal_sync_width <<
98 		       CRT_HORIZONTAL_SYNC_WIDTH_SHIFT) &
99 		     CRT_HORIZONTAL_SYNC_WIDTH_MASK;
100 		tmp |= (pModeParam->horizontal_sync_start - 1) &
101 		      CRT_HORIZONTAL_SYNC_START_MASK;
102 
103 		poke32(CRT_HORIZONTAL_SYNC, tmp);
104 
105 		tmp = ((pModeParam->vertical_total - 1) <<
106 		       CRT_VERTICAL_TOTAL_TOTAL_SHIFT) &
107 		     CRT_VERTICAL_TOTAL_TOTAL_MASK;
108 		tmp |= (pModeParam->vertical_display_end - 1) &
109 		      CRT_VERTICAL_TOTAL_DISPLAY_END_MASK;
110 
111 		poke32(CRT_VERTICAL_TOTAL, tmp);
112 
113 		tmp = ((pModeParam->vertical_sync_height <<
114 		       CRT_VERTICAL_SYNC_HEIGHT_SHIFT)) &
115 		     CRT_VERTICAL_SYNC_HEIGHT_MASK;
116 		tmp |= (pModeParam->vertical_sync_start - 1) &
117 		      CRT_VERTICAL_SYNC_START_MASK;
118 
119 		poke32(CRT_VERTICAL_SYNC, tmp);
120 
121 		tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
122 		if (pModeParam->vertical_sync_polarity)
123 			tmp |= DISPLAY_CTRL_VSYNC_PHASE;
124 		if (pModeParam->horizontal_sync_polarity)
125 			tmp |= DISPLAY_CTRL_HSYNC_PHASE;
126 
127 		if (sm750_get_chip_type() == SM750LE) {
128 			displayControlAdjust_SM750LE(pModeParam, tmp);
129 		} else {
130 			reg = peek32(CRT_DISPLAY_CTRL) &
131 				~(DISPLAY_CTRL_VSYNC_PHASE |
132 				  DISPLAY_CTRL_HSYNC_PHASE |
133 				  DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE);
134 
135 			poke32(CRT_DISPLAY_CTRL, tmp | reg);
136 		}
137 
138 	} else if (pll->clock_type == PRIMARY_PLL) {
139 		unsigned int reserved;
140 
141 		poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll));
142 
143 		reg = ((pModeParam->horizontal_total - 1) <<
144 			PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
145 			PANEL_HORIZONTAL_TOTAL_TOTAL_MASK;
146 		reg |= ((pModeParam->horizontal_display_end - 1) &
147 			PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK);
148 		poke32(PANEL_HORIZONTAL_TOTAL, reg);
149 
150 		poke32(PANEL_HORIZONTAL_SYNC,
151 		       ((pModeParam->horizontal_sync_width <<
152 			 PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT) &
153 			PANEL_HORIZONTAL_SYNC_WIDTH_MASK) |
154 		       ((pModeParam->horizontal_sync_start - 1) &
155 			PANEL_HORIZONTAL_SYNC_START_MASK));
156 
157 		poke32(PANEL_VERTICAL_TOTAL,
158 		       (((pModeParam->vertical_total - 1) <<
159 			 PANEL_VERTICAL_TOTAL_TOTAL_SHIFT) &
160 			PANEL_VERTICAL_TOTAL_TOTAL_MASK) |
161 		       ((pModeParam->vertical_display_end - 1) &
162 			PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK));
163 
164 		poke32(PANEL_VERTICAL_SYNC,
165 		       ((pModeParam->vertical_sync_height <<
166 			 PANEL_VERTICAL_SYNC_HEIGHT_SHIFT) &
167 			PANEL_VERTICAL_SYNC_HEIGHT_MASK) |
168 		       ((pModeParam->vertical_sync_start - 1) &
169 			PANEL_VERTICAL_SYNC_START_MASK));
170 
171 		tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
172 		if (pModeParam->vertical_sync_polarity)
173 			tmp |= DISPLAY_CTRL_VSYNC_PHASE;
174 		if (pModeParam->horizontal_sync_polarity)
175 			tmp |= DISPLAY_CTRL_HSYNC_PHASE;
176 		if (pModeParam->clock_phase_polarity)
177 			tmp |= DISPLAY_CTRL_CLOCK_PHASE;
178 
179 		reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK |
180 			PANEL_DISPLAY_CTRL_VSYNC;
181 
182 		reg = (peek32(PANEL_DISPLAY_CTRL) & ~reserved) &
183 			~(DISPLAY_CTRL_CLOCK_PHASE | DISPLAY_CTRL_VSYNC_PHASE |
184 			  DISPLAY_CTRL_HSYNC_PHASE | DISPLAY_CTRL_TIMING |
185 			  DISPLAY_CTRL_PLANE);
186 
187 		/*
188 		 * May a hardware bug or just my test chip (not confirmed).
189 		 * PANEL_DISPLAY_CTRL register seems requiring few writes
190 		 * before a value can be successfully written in.
191 		 * Added some masks to mask out the reserved bits.
192 		 * Note: This problem happens by design. The hardware will wait
193 		 *       for the next vertical sync to turn on/off the plane.
194 		 */
195 		poke32(PANEL_DISPLAY_CTRL, tmp | reg);
196 
197 		while ((peek32(PANEL_DISPLAY_CTRL) & ~reserved) !=
198 			(tmp | reg)) {
199 			cnt++;
200 			if (cnt > 1000)
201 				break;
202 			poke32(PANEL_DISPLAY_CTRL, tmp | reg);
203 		}
204 	} else {
205 		ret = -1;
206 	}
207 	return ret;
208 }
209 
210 int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock)
211 {
212 	struct pll_value pll;
213 
214 	pll.input_freq = DEFAULT_INPUT_CLOCK;
215 	pll.clock_type = clock;
216 
217 	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