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   *  sii164_get_vendor_id
33   *      This function gets the vendor ID of the DVI controller chip.
34   *
35   *  Output:
36   *      Vendor ID
37   */
sii164_get_vendor_id(void)38  unsigned 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   */
sii164GetDeviceID(void)57  unsigned 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   */
sii164_init_chip(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)121  long 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   */
sii164ResetChip(void)256  void 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   */
sii164GetChipString(void)270  char *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   */
sii164SetPower(unsigned char powerUp)282  void 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   */
304  static
sii164SelectHotPlugDetectionMode(enum sii164_hot_plug_mode hotPlugMode)305  void 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   */
sii164EnableHotPlugDetection(unsigned char enableHotPlug)337  void 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   */
sii164IsConnected(void)360  unsigned 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   */
sii164CheckInterrupt(void)380  unsigned 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   */
sii164ClearInterrupt(void)396  void 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