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 * edgeSelect - Edge Select:
73 * 0 = Input data is falling edge latched (falling edge
74 * latched first in dual edge mode)
75 * 1 = Input data is rising edge latched (rising edge
76 * latched first in dual edge mode)
77 * busSelect - Input Bus Select:
78 * 0 = Input data bus is 12-bits wide
79 * 1 = Input data bus is 24-bits wide
80 * dualEdgeClkSelect - Dual Edge Clock Select
81 * 0 = Input data is single edge latched
82 * 1 = Input data is dual edge latched
83 * hsyncEnable - Horizontal Sync Enable:
84 * 0 = HSYNC input is transmitted as fixed LOW
85 * 1 = HSYNC input is transmitted as is
86 * vsyncEnable - Vertical Sync Enable:
87 * 0 = VSYNC input is transmitted as fixed LOW
88 * 1 = VSYNC input is transmitted as is
89 * deskewEnable - De-skewing Enable:
90 * 0 = De-skew disabled
91 * 1 = De-skew enabled
92 * deskewSetting - 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 * continuousSyncEnable- SYNC Continuous:
102 * 0 = Disable
103 * 1 = Enable
104 * pllFilterEnable - PLL Filter Enable
105 * 0 = Disable PLL Filter
106 * 1 = Enable PLL Filter
107 * pllFilterValue - PLL Filter characteristics:
108 * 0~7 (recommended value is 4)
109 *
110 * Output:
111 * 0 - Success
112 * -1 - Fail.
113 */
sii164InitChip(unsigned char edgeSelect,unsigned char busSelect,unsigned char dualEdgeClkSelect,unsigned char hsyncEnable,unsigned char vsyncEnable,unsigned char deskewEnable,unsigned char deskewSetting,unsigned char continuousSyncEnable,unsigned char pllFilterEnable,unsigned char pllFilterValue)114 long sii164InitChip(unsigned char edgeSelect,
115 unsigned char busSelect,
116 unsigned char dualEdgeClkSelect,
117 unsigned char hsyncEnable,
118 unsigned char vsyncEnable,
119 unsigned char deskewEnable,
120 unsigned char deskewSetting,
121 unsigned char continuousSyncEnable,
122 unsigned char pllFilterEnable,
123 unsigned char pllFilterValue)
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 (edgeSelect == 0)
143 config = SII164_CONFIGURATION_LATCH_FALLING;
144 else
145 config = SII164_CONFIGURATION_LATCH_RISING;
146
147 /* Select bus wide */
148 if (busSelect == 0)
149 config |= SII164_CONFIGURATION_BUS_12BITS;
150 else
151 config |= SII164_CONFIGURATION_BUS_24BITS;
152
153 /* Select Dual/Single Edge Clock */
154 if (dualEdgeClkSelect == 0)
155 config |= SII164_CONFIGURATION_CLOCK_SINGLE;
156 else
157 config |= SII164_CONFIGURATION_CLOCK_DUAL;
158
159 /* Select HSync Enable */
160 if (hsyncEnable == 0)
161 config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW;
162 else
163 config |= SII164_CONFIGURATION_HSYNC_AS_IS;
164
165 /* Select VSync Enable */
166 if (vsyncEnable == 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 (deskewEnable == 0)
179 config = SII164_DESKEW_DISABLE;
180 else
181 config = SII164_DESKEW_ENABLE;
182
183 switch (deskewSetting) {
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 (continuousSyncEnable == 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 (pllFilterEnable == 0)
219 config |= SII164_PLL_FILTER_DISABLE;
220 else
221 config |= SII164_PLL_FILTER_ENABLE;
222
223 /* Set the PLL Filter value */
224 config |= ((pllFilterValue & 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