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