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 | display_control_adjust_SM750LE(struct mode_parameter *mode_param, |
18 | unsigned long disp_control) |
19 | { |
20 | unsigned long x, y; |
21 | |
22 | x = mode_param->horizontal_display_end; |
23 | y = mode_param->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, data: 0); |
32 | |
33 | poke32(CRT_AUTO_CENTERING_BR, |
34 | data: (((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 disp_control have been properly set before |
40 | * calling this function. |
41 | * This function only sets the extra fields in disp_control. |
42 | */ |
43 | |
44 | /* Clear bit 29:27 of display control register */ |
45 | disp_control &= ~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 | disp_control |= CRT_DISPLAY_CTRL_CLK_PLL41; |
51 | else if (x == 1024 && y == 768) |
52 | disp_control |= CRT_DISPLAY_CTRL_CLK_PLL65; |
53 | else if (x == 1152 && y == 864) |
54 | disp_control |= CRT_DISPLAY_CTRL_CLK_PLL80; |
55 | else if (x == 1280 && y == 768) |
56 | disp_control |= CRT_DISPLAY_CTRL_CLK_PLL80; |
57 | else if (x == 1280 && y == 720) |
58 | disp_control |= CRT_DISPLAY_CTRL_CLK_PLL74; |
59 | else if (x == 1280 && y == 960) |
60 | disp_control |= CRT_DISPLAY_CTRL_CLK_PLL108; |
61 | else if (x == 1280 && y == 1024) |
62 | disp_control |= CRT_DISPLAY_CTRL_CLK_PLL108; |
63 | else /* default to VGA clock */ |
64 | disp_control |= CRT_DISPLAY_CTRL_CLK_PLL25; |
65 | |
66 | /* Set bit 25:24 of display controller */ |
67 | disp_control |= (CRT_DISPLAY_CTRL_CRTSELECT | CRT_DISPLAY_CTRL_RGBBIT); |
68 | |
69 | /* Set bit 14 of display controller */ |
70 | disp_control |= DISPLAY_CTRL_CLOCK_PHASE; |
71 | |
72 | poke32(CRT_DISPLAY_CTRL, data: disp_control); |
73 | |
74 | return disp_control; |
75 | } |
76 | |
77 | /* only timing related registers will be programed */ |
78 | static void program_mode_registers(struct mode_parameter *mode_param, |
79 | struct pll_value *pll) |
80 | { |
81 | int cnt = 0; |
82 | unsigned int tmp, reg; |
83 | |
84 | if (pll->clock_type == SECONDARY_PLL) { |
85 | /* programe secondary pixel clock */ |
86 | poke32(CRT_PLL_CTRL, data: sm750_format_pll_reg(p_PLL: pll)); |
87 | |
88 | tmp = ((mode_param->horizontal_total - 1) << |
89 | CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT) & |
90 | CRT_HORIZONTAL_TOTAL_TOTAL_MASK; |
91 | tmp |= (mode_param->horizontal_display_end - 1) & |
92 | CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK; |
93 | |
94 | poke32(CRT_HORIZONTAL_TOTAL, data: tmp); |
95 | |
96 | tmp = (mode_param->horizontal_sync_width << |
97 | CRT_HORIZONTAL_SYNC_WIDTH_SHIFT) & |
98 | CRT_HORIZONTAL_SYNC_WIDTH_MASK; |
99 | tmp |= (mode_param->horizontal_sync_start - 1) & |
100 | CRT_HORIZONTAL_SYNC_START_MASK; |
101 | |
102 | poke32(CRT_HORIZONTAL_SYNC, data: tmp); |
103 | |
104 | tmp = ((mode_param->vertical_total - 1) << |
105 | CRT_VERTICAL_TOTAL_TOTAL_SHIFT) & |
106 | CRT_VERTICAL_TOTAL_TOTAL_MASK; |
107 | tmp |= (mode_param->vertical_display_end - 1) & |
108 | CRT_VERTICAL_TOTAL_DISPLAY_END_MASK; |
109 | |
110 | poke32(CRT_VERTICAL_TOTAL, data: tmp); |
111 | |
112 | tmp = ((mode_param->vertical_sync_height << |
113 | CRT_VERTICAL_SYNC_HEIGHT_SHIFT)) & |
114 | CRT_VERTICAL_SYNC_HEIGHT_MASK; |
115 | tmp |= (mode_param->vertical_sync_start - 1) & |
116 | CRT_VERTICAL_SYNC_START_MASK; |
117 | |
118 | poke32(CRT_VERTICAL_SYNC, data: tmp); |
119 | |
120 | tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE; |
121 | if (mode_param->vertical_sync_polarity) |
122 | tmp |= DISPLAY_CTRL_VSYNC_PHASE; |
123 | if (mode_param->horizontal_sync_polarity) |
124 | tmp |= DISPLAY_CTRL_HSYNC_PHASE; |
125 | |
126 | if (sm750_get_chip_type() == SM750LE) { |
127 | display_control_adjust_SM750LE(mode_param, disp_control: 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, data: tmp | reg); |
135 | } |
136 | |
137 | } else if (pll->clock_type == PRIMARY_PLL) { |
138 | unsigned int reserved; |
139 | |
140 | poke32(PANEL_PLL_CTRL, data: sm750_format_pll_reg(p_PLL: pll)); |
141 | |
142 | reg = ((mode_param->horizontal_total - 1) << |
143 | PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT) & |
144 | PANEL_HORIZONTAL_TOTAL_TOTAL_MASK; |
145 | reg |= ((mode_param->horizontal_display_end - 1) & |
146 | PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK); |
147 | poke32(PANEL_HORIZONTAL_TOTAL, data: reg); |
148 | |
149 | poke32(PANEL_HORIZONTAL_SYNC, |
150 | data: ((mode_param->horizontal_sync_width << |
151 | PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT) & |
152 | PANEL_HORIZONTAL_SYNC_WIDTH_MASK) | |
153 | ((mode_param->horizontal_sync_start - 1) & |
154 | PANEL_HORIZONTAL_SYNC_START_MASK)); |
155 | |
156 | poke32(PANEL_VERTICAL_TOTAL, |
157 | data: (((mode_param->vertical_total - 1) << |
158 | PANEL_VERTICAL_TOTAL_TOTAL_SHIFT) & |
159 | PANEL_VERTICAL_TOTAL_TOTAL_MASK) | |
160 | ((mode_param->vertical_display_end - 1) & |
161 | PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK)); |
162 | |
163 | poke32(PANEL_VERTICAL_SYNC, |
164 | data: ((mode_param->vertical_sync_height << |
165 | PANEL_VERTICAL_SYNC_HEIGHT_SHIFT) & |
166 | PANEL_VERTICAL_SYNC_HEIGHT_MASK) | |
167 | ((mode_param->vertical_sync_start - 1) & |
168 | PANEL_VERTICAL_SYNC_START_MASK)); |
169 | |
170 | tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE; |
171 | if (mode_param->vertical_sync_polarity) |
172 | tmp |= DISPLAY_CTRL_VSYNC_PHASE; |
173 | if (mode_param->horizontal_sync_polarity) |
174 | tmp |= DISPLAY_CTRL_HSYNC_PHASE; |
175 | if (mode_param->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, data: 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, data: tmp | reg); |
202 | } |
203 | } |
204 | } |
205 | |
206 | int ddk750_set_mode_timing(struct mode_parameter *parm, enum clock_type clock) |
207 | { |
208 | struct pll_value pll; |
209 | |
210 | pll.input_freq = DEFAULT_INPUT_CLOCK; |
211 | pll.clock_type = clock; |
212 | |
213 | sm750_calc_pll_value(request: parm->pixel_clock, pll: &pll); |
214 | if (sm750_get_chip_type() == SM750LE) { |
215 | /* set graphic mode via IO method */ |
216 | outb_p(value: 0x88, port: 0x3d4); |
217 | outb_p(value: 0x06, port: 0x3d5); |
218 | } |
219 | program_mode_registers(mode_param: parm, pll: &pll); |
220 | return 0; |
221 | } |
222 | |