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  */
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  */
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  */
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  */
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  */
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  */
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
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  */
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  */
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  */
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  */
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