]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
81dee67e | 2 | |
81dee67e SM |
3 | #include "ddk750_reg.h" |
4 | #include "ddk750_mode.h" | |
5 | #include "ddk750_chip.h" | |
6 | ||
f5016082 ES |
7 | /* |
8 | * SM750LE only: | |
35e4d8ca EF |
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 | */ | |
bf760231 AS |
16 | static unsigned long displayControlAdjust_SM750LE(struct mode_parameter *pModeParam, |
17 | unsigned long dispControl) | |
81dee67e SM |
18 | { |
19 | unsigned long x, y; | |
20 | ||
21 | x = pModeParam->horizontal_display_end; | |
22 | y = pModeParam->vertical_display_end; | |
23 | ||
f5016082 ES |
24 | /* |
25 | * SM750LE has to set up the top-left and bottom-right | |
35e4d8ca EF |
26 | * registers as well. |
27 | * Note that normal SM750/SM718 only use those two register for | |
28 | * auto-centering mode. | |
78376535 | 29 | */ |
c075b6f2 | 30 | poke32(CRT_AUTO_CENTERING_TL, 0); |
78376535 | 31 | |
c075b6f2 | 32 | poke32(CRT_AUTO_CENTERING_BR, |
4cd3096d AS |
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)); | |
78376535 | 36 | |
f5016082 ES |
37 | /* |
38 | * Assume common fields in dispControl have been properly set before | |
35e4d8ca EF |
39 | * calling this function. |
40 | * This function only sets the extra fields in dispControl. | |
78376535 | 41 | */ |
81dee67e SM |
42 | |
43 | /* Clear bit 29:27 of display control register */ | |
cdce1f18 | 44 | dispControl &= ~CRT_DISPLAY_CTRL_CLK_MASK; |
81dee67e SM |
45 | |
46 | /* Set bit 29:27 of display control register for the right clock */ | |
fbb8c963 | 47 | /* Note that SM750LE only need to supported 7 resolutions. */ |
8332d94c | 48 | if (x == 800 && y == 600) |
cdce1f18 | 49 | dispControl |= CRT_DISPLAY_CTRL_CLK_PLL41; |
81dee67e | 50 | else if (x == 1024 && y == 768) |
cdce1f18 | 51 | dispControl |= CRT_DISPLAY_CTRL_CLK_PLL65; |
81dee67e | 52 | else if (x == 1152 && y == 864) |
cdce1f18 | 53 | dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80; |
81dee67e | 54 | else if (x == 1280 && y == 768) |
cdce1f18 | 55 | dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80; |
81dee67e | 56 | else if (x == 1280 && y == 720) |
cdce1f18 | 57 | dispControl |= CRT_DISPLAY_CTRL_CLK_PLL74; |
81dee67e | 58 | else if (x == 1280 && y == 960) |
cdce1f18 | 59 | dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108; |
81dee67e | 60 | else if (x == 1280 && y == 1024) |
cdce1f18 | 61 | dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108; |
81dee67e | 62 | else /* default to VGA clock */ |
cdce1f18 | 63 | dispControl |= CRT_DISPLAY_CTRL_CLK_PLL25; |
81dee67e SM |
64 | |
65 | /* Set bit 25:24 of display controller */ | |
d8264edf | 66 | dispControl |= (CRT_DISPLAY_CTRL_CRTSELECT | CRT_DISPLAY_CTRL_RGBBIT); |
81dee67e | 67 | |
78376535 | 68 | /* Set bit 14 of display controller */ |
992f9614 | 69 | dispControl |= DISPLAY_CTRL_CLOCK_PHASE; |
81dee67e | 70 | |
c075b6f2 | 71 | poke32(CRT_DISPLAY_CTRL, dispControl); |
81dee67e SM |
72 | |
73 | return dispControl; | |
74 | } | |
75 | ||
81dee67e | 76 | /* only timing related registers will be programed */ |
bf760231 AS |
77 | static int programModeRegisters(struct mode_parameter *pModeParam, |
78 | struct pll_value *pll) | |
81dee67e SM |
79 | { |
80 | int ret = 0; | |
81 | int cnt = 0; | |
c436e6ba | 82 | unsigned int tmp, reg; |
40403c1b | 83 | |
259fef35 | 84 | if (pll->clockType == SECONDARY_PLL) { |
81dee67e | 85 | /* programe secondary pixel clock */ |
c075b6f2 | 86 | poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll)); |
7369e062 AS |
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); | |
81dee67e | 119 | |
6fba39cf MR |
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; | |
81dee67e | 125 | |
06a4f429 | 126 | if (sm750_get_chip_type() == SM750LE) { |
c436e6ba | 127 | displayControlAdjust_SM750LE(pModeParam, tmp); |
6338a781 | 128 | } else { |
c075b6f2 | 129 | reg = peek32(CRT_DISPLAY_CTRL) & |
6fba39cf MR |
130 | ~(DISPLAY_CTRL_VSYNC_PHASE | |
131 | DISPLAY_CTRL_HSYNC_PHASE | | |
132 | DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE); | |
81dee67e | 133 | |
c075b6f2 | 134 | poke32(CRT_DISPLAY_CTRL, tmp | reg); |
81dee67e SM |
135 | } |
136 | ||
259fef35 | 137 | } else if (pll->clockType == PRIMARY_PLL) { |
c436e6ba | 138 | unsigned int reserved; |
40403c1b | 139 | |
c075b6f2 | 140 | poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll)); |
81dee67e | 141 | |
60112069 MR |
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); | |
c075b6f2 | 147 | poke32(PANEL_HORIZONTAL_TOTAL, reg); |
81dee67e | 148 | |
c075b6f2 | 149 | poke32(PANEL_HORIZONTAL_SYNC, |
4cd3096d AS |
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)); | |
81dee67e | 155 | |
c075b6f2 | 156 | poke32(PANEL_VERTICAL_TOTAL, |
4cd3096d AS |
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)); | |
81dee67e | 162 | |
c075b6f2 | 163 | poke32(PANEL_VERTICAL_SYNC, |
4cd3096d AS |
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)); | |
81dee67e | 169 | |
6fba39cf MR |
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; | |
78376535 | 177 | |
9bd2c86b | 178 | reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK | |
6fba39cf | 179 | PANEL_DISPLAY_CTRL_VSYNC; |
81dee67e | 180 | |
c075b6f2 | 181 | reg = (peek32(PANEL_DISPLAY_CTRL) & ~reserved) & |
6fba39cf MR |
182 | ~(DISPLAY_CTRL_CLOCK_PHASE | DISPLAY_CTRL_VSYNC_PHASE | |
183 | DISPLAY_CTRL_HSYNC_PHASE | DISPLAY_CTRL_TIMING | | |
184 | DISPLAY_CTRL_PLANE); | |
81dee67e | 185 | |
f5016082 ES |
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 | */ | |
c075b6f2 | 194 | poke32(PANEL_DISPLAY_CTRL, tmp | reg); |
cfac7d6a | 195 | |
c075b6f2 | 196 | while ((peek32(PANEL_DISPLAY_CTRL) & ~reserved) != |
c436e6ba | 197 | (tmp | reg)) { |
81dee67e | 198 | cnt++; |
9ccc5f44 | 199 | if (cnt > 1000) |
81dee67e | 200 | break; |
c075b6f2 | 201 | poke32(PANEL_DISPLAY_CTRL, tmp | reg); |
81dee67e | 202 | } |
259fef35 | 203 | } else { |
81dee67e SM |
204 | ret = -1; |
205 | } | |
206 | return ret; | |
207 | } | |
208 | ||
17eb0b29 | 209 | int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock) |
81dee67e | 210 | { |
9872fa75 | 211 | struct pll_value pll; |
81dee67e | 212 | unsigned int uiActualPixelClk; |
40403c1b | 213 | |
81dee67e SM |
214 | pll.inputFreq = DEFAULT_INPUT_CLOCK; |
215 | pll.clockType = clock; | |
216 | ||
52d0744d | 217 | uiActualPixelClk = sm750_calc_pll_value(parm->pixel_clock, &pll); |
06a4f429 | 218 | if (sm750_get_chip_type() == SM750LE) { |
81dee67e | 219 | /* set graphic mode via IO method */ |
195d2b64 IA |
220 | outb_p(0x88, 0x3d4); |
221 | outb_p(0x06, 0x3d5); | |
81dee67e | 222 | } |
195d2b64 | 223 | programModeRegisters(parm, &pll); |
81dee67e SM |
224 | return 0; |
225 | } |