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 */
16static unsigned long
17display_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 */
78static 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
206int 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

source code of linux/drivers/staging/sm750fb/ddk750_mode.c