Lynx framebuffers multidomain implementation.
[linux/elbrus.git] / drivers / video / lynxfb / ddk750_mode.c
blob98adc390c5375a3d355bdb5118fc73b67dd56d9d
1 /*******************************************************************
2 *Copyright (c) 2012 by Silicon Motion, Inc. (SMI)
3 *Permission is hereby granted, free of charge, to any person obtaining a copy
4 *of this software and associated documentation files (the "Software"), to deal
5 *in the Software without restriction, including without limitation the rights to
6 *use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 *of the Software, and to permit persons to whom the Software is furnished to
8 *do so, subject to the following conditions:
10 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
12 *OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13 *NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT
14 *HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
15 *WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
16 *FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
17 *OTHER DEALINGS IN THE SOFTWARE.
18 *******************************************************************/
19 #include "ddk750_help.h"
20 #include "ddk750_reg.h"
21 #include "ddk750_mode.h"
22 #include "ddk750_chip.h"
24 #ifdef CONFIG_FB_LYNXFB_DOMAINS
26 SM750LE only:
27 This function takes care extra registers and bit fields required to set
28 up a mode in SM750LE
30 Explanation about Display Control register:
31 HW only supports 7 predefined pixel clocks, and clock select is
32 in bit 29:27 of Display Control register.
34 static unsigned long displayControlAdjust_SM750LE(mode_parameter_t *
35 pModeParam,
36 unsigned long
37 dispControl,
38 int domain)
40 unsigned long x, y;
42 x = pModeParam->horizontal_display_end;
43 y = pModeParam->vertical_display_end;
45 /* SM750LE has to set up the top-left and bottom-right
46 registers as well.
47 Note that normal SM750/SM718 only use those two register for
48 auto-centering mode.
50 POKE32(CRT_AUTO_CENTERING_TL,
51 (~(0x7FF << CRT_AUTO_CENTERING_TL_TOP_LSB)) &
52 (~(0x7FF << CRT_AUTO_CENTERING_TL_LEFT_LSB)), domain);
54 /*clear */
55 POKE32(CRT_AUTO_CENTERING_BR,
56 (~(0x7FF << CRT_AUTO_CENTERING_BR_BOTTOM_LSB)) |
57 (~(0x7FF << CRT_AUTO_CENTERING_BR_RIGHT_LSB)), domain);
58 POKE32(CRT_AUTO_CENTERING_BR,
59 ((y - 1) << CRT_AUTO_CENTERING_BR_BOTTOM_LSB) |
60 ((x - 1) << CRT_AUTO_CENTERING_BR_RIGHT_LSB), domain);
61 /* Clear bit 29:27 of display control register */
62 dispControl &= ~(7 << CRT_DISPLAY_CTRL_CLK_LSB);
63 /* Assume common fields in dispControl have been properly set before
64 calling this function.
65 This function only sets the extra fields in dispControl.
69 /* Set bit 29:27 of display control register for the right clock */
70 /* Note that SM750LE only need to supported 7 resoluitons. */
71 dispControl &= (~(7 << CRT_DISPLAY_CTRL_CLK_LSB));
72 if (x == 800 && y == 600)
73 dispControl |= 1 << CRT_DISPLAY_CTRL_CLK_LSB;
74 else if (x == 1024 && y == 768)
75 dispControl |= 3 << CRT_DISPLAY_CTRL_CLK_LSB;
76 else if (x == 1152 && y == 864)
77 dispControl |= 5 << CRT_DISPLAY_CTRL_CLK_LSB;
78 else if (x == 1280 && y == 768)
79 dispControl |= 5 << CRT_DISPLAY_CTRL_CLK_LSB;
80 else if (x == 1280 && y == 720)
81 dispControl |= 4 << CRT_DISPLAY_CTRL_CLK_LSB;
82 else if (x == 1280 && y == 960)
83 dispControl |= 6 << CRT_DISPLAY_CTRL_CLK_LSB;
84 else if (x == 1280 && y == 1024)
85 dispControl |= 6 << CRT_DISPLAY_CTRL_CLK_LSB;
86 else /* default to VGA clock */
87 dispControl &= ~(7 << CRT_DISPLAY_CTRL_CLK_LSB);
89 /* Set bit 25:24 of display controller */
90 dispControl |= 1 << CRT_DISPLAY_CTRL_CRTSELECT_LSB;
91 dispControl &= ~(1 << CRT_DISPLAY_CTRL_RGBBIT_LSB);
93 /* Set bit 14 of display controller */
94 dispControl |= 1 << CRT_DISPLAY_CTRL_CLOCK_PHASE_LSB;
95 POKE32(CRT_DISPLAY_CTRL, dispControl, domain);
97 return dispControl;
101 /* only timing related registers will be programed */
102 static int programModeRegisters(mode_parameter_t * pModeParam,
103 pll_value_t * pll, int domain)
105 int ret = 0;
106 int cnt = 0;
107 unsigned int ulTmpValue, ulReg;
108 if (pll->clockType == SECONDARY_PLL) {
109 /* programe secondary pixel clock */
110 POKE32(CRT_PLL_CTRL, formatPllReg(pll), domain);
111 POKE32(CRT_HORIZONTAL_TOTAL,
112 ((pModeParam->horizontal_total -
113 1) << CRT_HORIZONTAL_TOTAL_TOTAL_LSB)
114 | ((pModeParam->horizontal_display_end - 1) <<
115 CRT_HORIZONTAL_TOTAL_DISPLAY_END_LSB), domain);
117 POKE32(CRT_HORIZONTAL_SYNC,
118 (pModeParam->
119 horizontal_sync_width <<
120 CRT_HORIZONTAL_SYNC_WIDTH_LSB)
121 | ((pModeParam->horizontal_sync_start - 1) <<
122 CRT_HORIZONTAL_SYNC_START_LSB), domain);
124 POKE32(CRT_VERTICAL_TOTAL,
125 ((pModeParam->vertical_total -
126 1) << CRT_VERTICAL_TOTAL_TOTAL_LSB)
127 | ((pModeParam->vertical_display_end - 1) <<
128 CRT_VERTICAL_TOTAL_DISPLAY_END_LSB), domain);
129 POKE32(CRT_VERTICAL_SYNC,
130 (pModeParam->
131 vertical_sync_height <<
132 CRT_VERTICAL_SYNC_HEIGHT_LSB)
133 | ((pModeParam->vertical_sync_start - 1) <<
134 CRT_VERTICAL_SYNC_START_LSB), domain);
137 ulTmpValue =
138 (pModeParam->
139 vertical_sync_polarity <<
140 CRT_DISPLAY_CTRL_VSYNC_PHASE_LSB) | (pModeParam->
141 horizontal_sync_polarity
143 CRT_DISPLAY_CTRL_HSYNC_PHASE_LSB)
144 | (1 << CRT_DISPLAY_CTRL_TIMING_LSB) | (1 <<
145 CRT_DISPLAY_CTRL_PLANE_LSB);
147 if (getChipType(domain) == SM750LE) {
148 displayControlAdjust_SM750LE(pModeParam,
149 ulTmpValue, domain);
150 } else {
151 ulReg = PEEK32(CRT_DISPLAY_CTRL, domain)
152 & (~(1 << CRT_DISPLAY_CTRL_VSYNC_PHASE_LSB))
153 & (~(1 << CRT_DISPLAY_CTRL_HSYNC_PHASE_LSB))
154 & (~(1 << CRT_DISPLAY_CTRL_TIMING_LSB))
155 & (~(1 << CRT_DISPLAY_CTRL_PLANE_LSB));
156 POKE32(CRT_DISPLAY_CTRL, ulTmpValue | ulReg, domain);
159 } else if (pll->clockType == PRIMARY_PLL) {
160 unsigned int ulReservedBits;
161 POKE32(PANEL_PLL_CTRL, formatPllReg(pll), domain);
162 POKE32(PANEL_HORIZONTAL_TOTAL,
163 ((pModeParam->horizontal_total -
164 1) << PANEL_HORIZONTAL_TOTAL_TOTAL_LSB)
165 | ((pModeParam->horizontal_display_end - 1) <<
166 PANEL_HORIZONTAL_TOTAL_DISPLAY_END_LSB), domain);
168 POKE32(PANEL_HORIZONTAL_SYNC,
169 (pModeParam->
170 horizontal_sync_width <<
171 PANEL_HORIZONTAL_SYNC_WIDTH_LSB)
172 | ((pModeParam->horizontal_sync_start - 1) <<
173 PANEL_HORIZONTAL_SYNC_START_LSB), domain);
175 POKE32(PANEL_VERTICAL_TOTAL,
176 ((pModeParam->vertical_total - 1)
177 << PANEL_VERTICAL_TOTAL_TOTAL_LSB)
178 | ((pModeParam->vertical_display_end - 1) <<
179 PANEL_VERTICAL_TOTAL_DISPLAY_END_LSB), domain);
181 POKE32(PANEL_VERTICAL_SYNC,
182 (pModeParam->vertical_sync_height <<
183 PANEL_VERTICAL_SYNC_HEIGHT_LSB)
184 | ((pModeParam->vertical_sync_start - 1) <<
185 PANEL_VERTICAL_SYNC_START_LSB), domain);
186 ulTmpValue =
187 (pModeParam->vertical_sync_polarity <<
188 PANEL_DISPLAY_CTRL_VSYNC_PHASE_LSB)
189 | (pModeParam->horizontal_sync_polarity <<
190 PANEL_DISPLAY_CTRL_HSYNC_PHASE_LSB)
191 | (pModeParam->clock_phase_polarity <<
192 PANEL_DISPLAY_CTRL_CLOCK_PHASE_LSB)
193 | (1 << PANEL_DISPLAY_CTRL_TIMING_LSB)
194 | (1 << PANEL_DISPLAY_CTRL_PLANE_LSB);
195 ulReservedBits =
196 (3 << PANEL_DISPLAY_CTRL_RESERVED_1_MASK_LSB) | (15 <<
197 PANEL_DISPLAY_CTRL_RESERVED_2_MASK_LSB)
198 | (1 << PANEL_DISPLAY_CTRL_RESERVED_3_MASK_LSB) | (1 <<
199 PANEL_DISPLAY_CTRL_VSYNC_LSB);
200 ulReg = (PEEK32(PANEL_DISPLAY_CTRL, domain) & ~ulReservedBits)
201 & (~(1 << PANEL_DISPLAY_CTRL_CLOCK_PHASE_LSB))
202 & (~(1 << PANEL_DISPLAY_CTRL_VSYNC_PHASE_LSB))
203 & (~(1 << PANEL_DISPLAY_CTRL_HSYNC_PHASE_LSB))
204 & (~(1 << PANEL_DISPLAY_CTRL_TIMING_LSB))
205 & (~(1 << PANEL_DISPLAY_CTRL_PLANE_LSB));
207 /* May a hardware bug or just my test chip (not confirmed).
208 * PANEL_DISPLAY_CTRL register seems requiring few writes
209 * before a value can be succesfully written in.
210 * Added some masks to mask out the reserved bits.
211 * Note: This problem happens by design. The hardware will wait for the
212 * next vertical sync to turn on/off the plane.
215 POKE32(PANEL_DISPLAY_CTRL, ulTmpValue | ulReg, domain);
217 while ((PEEK32(PANEL_DISPLAY_CTRL, domain) & ~ulReservedBits) !=
218 (ulTmpValue | ulReg)) {
219 cnt++;
220 if (cnt > 1000)
221 break;
222 POKE32(PANEL_DISPLAY_CTRL, ulTmpValue | ulReg, domain);
225 } else {
226 ret = -1;
228 return ret;
231 int ddk750_setModeTiming(mode_parameter_t * parm, clock_type_t clock, int domain)
233 pll_value_t pll;
234 unsigned int uiActualPixelClk;
235 pll.inputFreq = DEFAULT_INPUT_CLOCK;
236 pll.clockType = clock;
238 uiActualPixelClk = calcPllValue(parm->pixel_clock, &pll, domain);
239 if (getChipType(domain) == SM750LE) {
240 /* set graphic mode via IO method */
241 outb_p(0x88, 0x3d4);
242 outb_p(0x06, 0x3d5);
244 programModeRegisters(parm, &pll, domain);
245 return 0;
248 #else /* !CONFIG_FB_LYNXFB_DOMAINS: */
250 SM750LE only:
251 This function takes care extra registers and bit fields required to set
252 up a mode in SM750LE
254 Explanation about Display Control register:
255 HW only supports 7 predefined pixel clocks, and clock select is
256 in bit 29:27 of Display Control register.
258 static unsigned long displayControlAdjust_SM750LE(mode_parameter_t *
259 pModeParam,
260 unsigned long
261 dispControl)
263 unsigned long x, y;
265 x = pModeParam->horizontal_display_end;
266 y = pModeParam->vertical_display_end;
268 /* SM750LE has to set up the top-left and bottom-right
269 registers as well.
270 Note that normal SM750/SM718 only use those two register for
271 auto-centering mode.
273 POKE32(CRT_AUTO_CENTERING_TL,
274 (~(0x7FF << CRT_AUTO_CENTERING_TL_TOP_LSB)) &
275 (~(0x7FF << CRT_AUTO_CENTERING_TL_LEFT_LSB)));
277 /*clear */
278 POKE32(CRT_AUTO_CENTERING_BR,
279 (~(0x7FF << CRT_AUTO_CENTERING_BR_BOTTOM_LSB)) |
280 (~(0x7FF << CRT_AUTO_CENTERING_BR_RIGHT_LSB)));
281 POKE32(CRT_AUTO_CENTERING_BR,
282 ((y - 1) << CRT_AUTO_CENTERING_BR_BOTTOM_LSB) |
283 ((x - 1) << CRT_AUTO_CENTERING_BR_RIGHT_LSB));
284 /* Clear bit 29:27 of display control register */
285 dispControl &= ~(7 << CRT_DISPLAY_CTRL_CLK_LSB);
286 /* Assume common fields in dispControl have been properly set before
287 calling this function.
288 This function only sets the extra fields in dispControl.
292 /* Set bit 29:27 of display control register for the right clock */
293 /* Note that SM750LE only need to supported 7 resoluitons. */
294 dispControl &= (~(7 << CRT_DISPLAY_CTRL_CLK_LSB));
295 if (x == 800 && y == 600)
296 dispControl |= 1 << CRT_DISPLAY_CTRL_CLK_LSB;
297 else if (x == 1024 && y == 768)
298 dispControl |= 3 << CRT_DISPLAY_CTRL_CLK_LSB;
299 else if (x == 1152 && y == 864)
300 dispControl |= 5 << CRT_DISPLAY_CTRL_CLK_LSB;
301 else if (x == 1280 && y == 768)
302 dispControl |= 5 << CRT_DISPLAY_CTRL_CLK_LSB;
303 else if (x == 1280 && y == 720)
304 dispControl |= 4 << CRT_DISPLAY_CTRL_CLK_LSB;
305 else if (x == 1280 && y == 960)
306 dispControl |= 6 << CRT_DISPLAY_CTRL_CLK_LSB;
307 else if (x == 1280 && y == 1024)
308 dispControl |= 6 << CRT_DISPLAY_CTRL_CLK_LSB;
309 else /* default to VGA clock */
310 dispControl &= ~(7 << CRT_DISPLAY_CTRL_CLK_LSB);
312 /* Set bit 25:24 of display controller */
313 dispControl |= 1 << CRT_DISPLAY_CTRL_CRTSELECT_LSB;
314 dispControl &= ~(1 << CRT_DISPLAY_CTRL_RGBBIT_LSB);
316 /* Set bit 14 of display controller */
317 dispControl |= 1 << CRT_DISPLAY_CTRL_CLOCK_PHASE_LSB;
318 POKE32(CRT_DISPLAY_CTRL, dispControl);
320 return dispControl;
326 /* only timing related registers will be programed */
327 static int programModeRegisters(mode_parameter_t * pModeParam,
328 pll_value_t * pll)
330 int ret = 0;
331 int cnt = 0;
332 unsigned int ulTmpValue, ulReg;
333 if (pll->clockType == SECONDARY_PLL) {
334 /* programe secondary pixel clock */
335 POKE32(CRT_PLL_CTRL, formatPllReg(pll));
336 POKE32(CRT_HORIZONTAL_TOTAL,
337 ((pModeParam->horizontal_total -
338 1) << CRT_HORIZONTAL_TOTAL_TOTAL_LSB)
339 | ((pModeParam->horizontal_display_end - 1) <<
340 CRT_HORIZONTAL_TOTAL_DISPLAY_END_LSB));
342 POKE32(CRT_HORIZONTAL_SYNC,
343 (pModeParam->
344 horizontal_sync_width <<
345 CRT_HORIZONTAL_SYNC_WIDTH_LSB)
346 | ((pModeParam->horizontal_sync_start - 1) <<
347 CRT_HORIZONTAL_SYNC_START_LSB));
349 POKE32(CRT_VERTICAL_TOTAL,
350 ((pModeParam->vertical_total -
351 1) << CRT_VERTICAL_TOTAL_TOTAL_LSB)
352 | ((pModeParam->vertical_display_end - 1) <<
353 CRT_VERTICAL_TOTAL_DISPLAY_END_LSB));
354 POKE32(CRT_VERTICAL_SYNC,
355 (pModeParam->
356 vertical_sync_height <<
357 CRT_VERTICAL_SYNC_HEIGHT_LSB)
358 | ((pModeParam->vertical_sync_start - 1) <<
359 CRT_VERTICAL_SYNC_START_LSB));
362 ulTmpValue =
363 (pModeParam->
364 vertical_sync_polarity <<
365 CRT_DISPLAY_CTRL_VSYNC_PHASE_LSB) | (pModeParam->
366 horizontal_sync_polarity
368 CRT_DISPLAY_CTRL_HSYNC_PHASE_LSB)
369 | (1 << CRT_DISPLAY_CTRL_TIMING_LSB) | (1 <<
370 CRT_DISPLAY_CTRL_PLANE_LSB);
372 if (getChipType() == SM750LE) {
373 displayControlAdjust_SM750LE(pModeParam,
374 ulTmpValue);
375 } else {
376 ulReg = PEEK32(CRT_DISPLAY_CTRL)
377 & (~(1 << CRT_DISPLAY_CTRL_VSYNC_PHASE_LSB))
378 & (~(1 << CRT_DISPLAY_CTRL_HSYNC_PHASE_LSB))
379 & (~(1 << CRT_DISPLAY_CTRL_TIMING_LSB))
380 & (~(1 << CRT_DISPLAY_CTRL_PLANE_LSB));
381 POKE32(CRT_DISPLAY_CTRL, ulTmpValue | ulReg);
384 } else if (pll->clockType == PRIMARY_PLL) {
385 unsigned int ulReservedBits;
386 POKE32(PANEL_PLL_CTRL, formatPllReg(pll));
387 POKE32(PANEL_HORIZONTAL_TOTAL,
388 ((pModeParam->horizontal_total -
389 1) << PANEL_HORIZONTAL_TOTAL_TOTAL_LSB)
390 | ((pModeParam->horizontal_display_end - 1) <<
391 PANEL_HORIZONTAL_TOTAL_DISPLAY_END_LSB));
393 POKE32(PANEL_HORIZONTAL_SYNC,
394 (pModeParam->
395 horizontal_sync_width <<
396 PANEL_HORIZONTAL_SYNC_WIDTH_LSB)
397 | ((pModeParam->horizontal_sync_start - 1) <<
398 PANEL_HORIZONTAL_SYNC_START_LSB));
400 POKE32(PANEL_VERTICAL_TOTAL,
401 ((pModeParam->vertical_total - 1)
402 << PANEL_VERTICAL_TOTAL_TOTAL_LSB)
403 | ((pModeParam->vertical_display_end - 1) <<
404 PANEL_VERTICAL_TOTAL_DISPLAY_END_LSB));
406 POKE32(PANEL_VERTICAL_SYNC,
407 (pModeParam->vertical_sync_height <<
408 PANEL_VERTICAL_SYNC_HEIGHT_LSB)
409 | ((pModeParam->vertical_sync_start - 1) <<
410 PANEL_VERTICAL_SYNC_START_LSB));
411 ulTmpValue =
412 (pModeParam->vertical_sync_polarity <<
413 PANEL_DISPLAY_CTRL_VSYNC_PHASE_LSB)
414 | (pModeParam->horizontal_sync_polarity <<
415 PANEL_DISPLAY_CTRL_HSYNC_PHASE_LSB)
416 | (pModeParam->clock_phase_polarity <<
417 PANEL_DISPLAY_CTRL_CLOCK_PHASE_LSB)
418 | (1 << PANEL_DISPLAY_CTRL_TIMING_LSB)
419 | (1 << PANEL_DISPLAY_CTRL_PLANE_LSB);
420 ulReservedBits =
421 (3 << PANEL_DISPLAY_CTRL_RESERVED_1_MASK_LSB) | (15 <<
422 PANEL_DISPLAY_CTRL_RESERVED_2_MASK_LSB)
423 | (1 << PANEL_DISPLAY_CTRL_RESERVED_3_MASK_LSB) | (1 <<
424 PANEL_DISPLAY_CTRL_VSYNC_LSB);
425 ulReg = (PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits)
426 & (~(1 << PANEL_DISPLAY_CTRL_CLOCK_PHASE_LSB))
427 & (~(1 << PANEL_DISPLAY_CTRL_VSYNC_PHASE_LSB))
428 & (~(1 << PANEL_DISPLAY_CTRL_HSYNC_PHASE_LSB))
429 & (~(1 << PANEL_DISPLAY_CTRL_TIMING_LSB))
430 & (~(1 << PANEL_DISPLAY_CTRL_PLANE_LSB));
432 /* May a hardware bug or just my test chip (not confirmed).
433 * PANEL_DISPLAY_CTRL register seems requiring few writes
434 * before a value can be succesfully written in.
435 * Added some masks to mask out the reserved bits.
436 * Note: This problem happens by design. The hardware will wait for the
437 * next vertical sync to turn on/off the plane.
440 POKE32(PANEL_DISPLAY_CTRL, ulTmpValue | ulReg);
442 while ((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) !=
443 (ulTmpValue | ulReg)) {
444 cnt++;
445 if (cnt > 1000)
446 break;
447 POKE32(PANEL_DISPLAY_CTRL, ulTmpValue | ulReg);
450 } else {
451 ret = -1;
453 return ret;
456 int ddk750_setModeTiming(mode_parameter_t * parm, clock_type_t clock)
458 pll_value_t pll;
459 unsigned int uiActualPixelClk;
460 pll.inputFreq = DEFAULT_INPUT_CLOCK;
461 pll.clockType = clock;
463 uiActualPixelClk = calcPllValue(parm->pixel_clock, &pll);
464 if (getChipType() == SM750LE) {
465 /* set graphic mode via IO method */
466 outb_p(0x88, 0x3d4);
467 outb_p(0x06, 0x3d5);
469 programModeRegisters(parm, &pll);
470 return 0;
472 #endif /* !CONFIG_FB_LYNXFB_DOMAINS */