Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / drivers / staging / sm750fb / ddk750_mode.c
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 }