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