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