1 // SPDX-License-Identifier: GPL-2.0
2 #define USE_DVICHIP
3 #ifdef USE_DVICHIP
4
5 #include "ddk750_sii164.h"
6 #include "ddk750_hwi2c.h"
7
8 /* I2C Address of each SII164 chip */
9 #define SII164_I2C_ADDRESS 0x70
10
11 /* Define this definition to use hardware i2c. */
12 #define USE_HW_I2C
13
14 #ifdef USE_HW_I2C
15 #define i2cWriteReg sm750_hw_i2c_write_reg
16 #define i2cReadReg sm750_hw_i2c_read_reg
17 #else
18 #define i2cWriteReg sm750_sw_i2c_write_reg
19 #define i2cReadReg sm750_sw_i2c_read_reg
20 #endif
21
22 /* SII164 Vendor and Device ID */
23 #define SII164_VENDOR_ID 0x0001
24 #define SII164_DEVICE_ID 0x0006
25
26 #ifdef SII164_FULL_FUNCTIONS
27 /* Name of the DVI Controller chip */
28 static char *gDviCtrlChipName = "Silicon Image SiI 164";
29 #endif
30
31 /*
32 * sii164GetVendorID
33 * This function gets the vendor ID of the DVI controller chip.
34 *
35 * Output:
36 * Vendor ID
37 */
sii164GetVendorID(void)38 unsigned short sii164GetVendorID(void)
39 {
40 unsigned short vendorID;
41
42 vendorID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_HIGH) << 8) |
43 (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_LOW);
44
45 return vendorID;
46 }
47
48 /*
49 * sii164GetDeviceID
50 * This function gets the device ID of the DVI controller chip.
51 *
52 * Output:
53 * Device ID
54 */
sii164GetDeviceID(void)55 unsigned short sii164GetDeviceID(void)
56 {
57 unsigned short deviceID;
58
59 deviceID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_HIGH) << 8) |
60 (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_LOW);
61
62 return deviceID;
63 }
64
65 /* DVI.C will handle all SiI164 chip stuffs and try it best to make code minimal and useful */
66
67 /*
68 * sii164InitChip
69 * This function initialize and detect the DVI controller chip.
70 *
71 * Input:
72 * edge_select - Edge Select:
73 * 0 = Input data is falling edge latched (falling
74 * edge latched first in dual edge mode)
75 * 1 = Input data is rising edge latched (rising
76 * edge latched first in dual edge mode)
77 * bus_select - Input Bus Select:
78 * 0 = Input data bus is 12-bits wide
79 * 1 = Input data bus is 24-bits wide
80 * dual_edge_clk_select - Dual Edge Clock Select
81 * 0 = Input data is single edge latched
82 * 1 = Input data is dual edge latched
83 * hsync_enable - Horizontal Sync Enable:
84 * 0 = HSYNC input is transmitted as fixed LOW
85 * 1 = HSYNC input is transmitted as is
86 * vsync_enable - Vertical Sync Enable:
87 * 0 = VSYNC input is transmitted as fixed LOW
88 * 1 = VSYNC input is transmitted as is
89 * deskew_enable - De-skewing Enable:
90 * 0 = De-skew disabled
91 * 1 = De-skew enabled
92 * deskew_setting - De-skewing Setting (increment of 260psec)
93 * 0 = 1 step --> minimum setup / maximum hold
94 * 1 = 2 step
95 * 2 = 3 step
96 * 3 = 4 step
97 * 4 = 5 step
98 * 5 = 6 step
99 * 6 = 7 step
100 * 7 = 8 step --> maximum setup / minimum hold
101 * continuous_sync_enable- SYNC Continuous:
102 * 0 = Disable
103 * 1 = Enable
104 * pll_filter_enable - PLL Filter Enable
105 * 0 = Disable PLL Filter
106 * 1 = Enable PLL Filter
107 * pll_filter_value - PLL Filter characteristics:
108 * 0~7 (recommended value is 4)
109 *
110 * Output:
111 * 0 - Success
112 * -1 - Fail.
113 */
sii164InitChip(unsigned char edge_select,unsigned char bus_select,unsigned char dual_edge_clk_select,unsigned char hsync_enable,unsigned char vsync_enable,unsigned char deskew_enable,unsigned char deskew_setting,unsigned char continuous_sync_enable,unsigned char pll_filter_enable,unsigned char pll_filter_value)114 long sii164InitChip(unsigned char edge_select,
115 unsigned char bus_select,
116 unsigned char dual_edge_clk_select,
117 unsigned char hsync_enable,
118 unsigned char vsync_enable,
119 unsigned char deskew_enable,
120 unsigned char deskew_setting,
121 unsigned char continuous_sync_enable,
122 unsigned char pll_filter_enable,
123 unsigned char pll_filter_value)
124 {
125 unsigned char config;
126
127 /* Initialize the i2c bus */
128 #ifdef USE_HW_I2C
129 /* Use fast mode. */
130 sm750_hw_i2c_init(1);
131 #else
132 sm750_sw_i2c_init(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA);
133 #endif
134
135 /* Check if SII164 Chip exists */
136 if ((sii164GetVendorID() == SII164_VENDOR_ID) && (sii164GetDeviceID() == SII164_DEVICE_ID)) {
137 /*
138 * Initialize SII164 controller chip.
139 */
140
141 /* Select the edge */
142 if (edge_select == 0)
143 config = SII164_CONFIGURATION_LATCH_FALLING;
144 else
145 config = SII164_CONFIGURATION_LATCH_RISING;
146
147 /* Select bus wide */
148 if (bus_select == 0)
149 config |= SII164_CONFIGURATION_BUS_12BITS;
150 else
151 config |= SII164_CONFIGURATION_BUS_24BITS;
152
153 /* Select Dual/Single Edge Clock */
154 if (dual_edge_clk_select == 0)
155 config |= SII164_CONFIGURATION_CLOCK_SINGLE;
156 else
157 config |= SII164_CONFIGURATION_CLOCK_DUAL;
158
159 /* Select HSync Enable */
160 if (hsync_enable == 0)
161 config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW;
162 else
163 config |= SII164_CONFIGURATION_HSYNC_AS_IS;
164
165 /* Select VSync Enable */
166 if (vsync_enable == 0)
167 config |= SII164_CONFIGURATION_VSYNC_FORCE_LOW;
168 else
169 config |= SII164_CONFIGURATION_VSYNC_AS_IS;
170
171 i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
172
173 /*
174 * De-skew enabled with default 111b value.
175 * This fixes some artifacts problem in some mode on board 2.2.
176 * Somehow this fix does not affect board 2.1.
177 */
178 if (deskew_enable == 0)
179 config = SII164_DESKEW_DISABLE;
180 else
181 config = SII164_DESKEW_ENABLE;
182
183 switch (deskew_setting) {
184 case 0:
185 config |= SII164_DESKEW_1_STEP;
186 break;
187 case 1:
188 config |= SII164_DESKEW_2_STEP;
189 break;
190 case 2:
191 config |= SII164_DESKEW_3_STEP;
192 break;
193 case 3:
194 config |= SII164_DESKEW_4_STEP;
195 break;
196 case 4:
197 config |= SII164_DESKEW_5_STEP;
198 break;
199 case 5:
200 config |= SII164_DESKEW_6_STEP;
201 break;
202 case 6:
203 config |= SII164_DESKEW_7_STEP;
204 break;
205 case 7:
206 config |= SII164_DESKEW_8_STEP;
207 break;
208 }
209 i2cWriteReg(SII164_I2C_ADDRESS, SII164_DESKEW, config);
210
211 /* Enable/Disable Continuous Sync. */
212 if (continuous_sync_enable == 0)
213 config = SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE;
214 else
215 config = SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE;
216
217 /* Enable/Disable PLL Filter */
218 if (pll_filter_enable == 0)
219 config |= SII164_PLL_FILTER_DISABLE;
220 else
221 config |= SII164_PLL_FILTER_ENABLE;
222
223 /* Set the PLL Filter value */
224 config |= ((pll_filter_value & 0x07) << 1);
225
226 i2cWriteReg(SII164_I2C_ADDRESS, SII164_PLL, config);
227
228 /* Recover from Power Down and enable output. */
229 config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION);
230 config |= SII164_CONFIGURATION_POWER_NORMAL;
231 i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
232
233 return 0;
234 }
235
236 /* Return -1 if initialization fails. */
237 return -1;
238 }
239
240 /* below sii164 function is not necessary */
241
242 #ifdef SII164_FULL_FUNCTIONS
243
244 /*
245 * sii164ResetChip
246 * This function resets the DVI Controller Chip.
247 */
sii164ResetChip(void)248 void sii164ResetChip(void)
249 {
250 /* Power down */
251 sii164SetPower(0);
252 sii164SetPower(1);
253 }
254
255 /*
256 * sii164GetChipString
257 * This function returns a char string name of the current DVI Controller chip.
258 * It's convenient for application need to display the chip name.
259 */
sii164GetChipString(void)260 char *sii164GetChipString(void)
261 {
262 return gDviCtrlChipName;
263 }
264
265 /*
266 * sii164SetPower
267 * This function sets the power configuration of the DVI Controller Chip.
268 *
269 * Input:
270 * powerUp - Flag to set the power down or up
271 */
sii164SetPower(unsigned char powerUp)272 void sii164SetPower(unsigned char powerUp)
273 {
274 unsigned char config;
275
276 config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION);
277 if (powerUp == 1) {
278 /* Power up the chip */
279 config &= ~SII164_CONFIGURATION_POWER_MASK;
280 config |= SII164_CONFIGURATION_POWER_NORMAL;
281 i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
282 } else {
283 /* Power down the chip */
284 config &= ~SII164_CONFIGURATION_POWER_MASK;
285 config |= SII164_CONFIGURATION_POWER_DOWN;
286 i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
287 }
288 }
289
290 /*
291 * sii164SelectHotPlugDetectionMode
292 * This function selects the mode of the hot plug detection.
293 */
294 static
sii164SelectHotPlugDetectionMode(enum sii164_hot_plug_mode hotPlugMode)295 void sii164SelectHotPlugDetectionMode(enum sii164_hot_plug_mode hotPlugMode)
296 {
297 unsigned char detectReg;
298
299 detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) &
300 ~SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG;
301 switch (hotPlugMode) {
302 case SII164_HOTPLUG_DISABLE:
303 detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH;
304 break;
305 case SII164_HOTPLUG_USE_MDI:
306 detectReg &= ~SII164_DETECT_INTERRUPT_MASK;
307 detectReg |= SII164_DETECT_INTERRUPT_BY_HTPLG_PIN;
308 detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI;
309 break;
310 case SII164_HOTPLUG_USE_RSEN:
311 detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN;
312 break;
313 case SII164_HOTPLUG_USE_HTPLG:
314 detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG;
315 break;
316 }
317
318 i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg);
319 }
320
321 /*
322 * sii164EnableHotPlugDetection
323 * This function enables the Hot Plug detection.
324 *
325 * enableHotPlug - Enable (=1) / disable (=0) Hot Plug detection
326 */
sii164EnableHotPlugDetection(unsigned char enableHotPlug)327 void sii164EnableHotPlugDetection(unsigned char enableHotPlug)
328 {
329 unsigned char detectReg;
330
331 detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT);
332
333 /* Depending on each DVI controller, need to enable the hot plug based on each
334 * individual chip design.
335 */
336 if (enableHotPlug != 0)
337 sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_USE_MDI);
338 else
339 sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_DISABLE);
340 }
341
342 /*
343 * sii164IsConnected
344 * Check if the DVI Monitor is connected.
345 *
346 * Output:
347 * 0 - Not Connected
348 * 1 - Connected
349 */
sii164IsConnected(void)350 unsigned char sii164IsConnected(void)
351 {
352 unsigned char hotPlugValue;
353
354 hotPlugValue = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) &
355 SII164_DETECT_HOT_PLUG_STATUS_MASK;
356 if (hotPlugValue == SII164_DETECT_HOT_PLUG_STATUS_ON)
357 return 1;
358 else
359 return 0;
360 }
361
362 /*
363 * sii164CheckInterrupt
364 * Checks if interrupt has occurred.
365 *
366 * Output:
367 * 0 - No interrupt
368 * 1 - Interrupt occurs
369 */
sii164CheckInterrupt(void)370 unsigned char sii164CheckInterrupt(void)
371 {
372 unsigned char detectReg;
373
374 detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) &
375 SII164_DETECT_MONITOR_STATE_MASK;
376 if (detectReg == SII164_DETECT_MONITOR_STATE_CHANGE)
377 return 1;
378 else
379 return 0;
380 }
381
382 /*
383 * sii164ClearInterrupt
384 * Clear the hot plug interrupt.
385 */
sii164ClearInterrupt(void)386 void sii164ClearInterrupt(void)
387 {
388 unsigned char detectReg;
389
390 /* Clear the MDI interrupt */
391 detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT);
392 i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT,
393 detectReg | SII164_DETECT_MONITOR_STATE_CLEAR);
394 }
395
396 #endif
397
398 #endif
399