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 | */ |
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 | */ |
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 | */ |
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(bus_speed_mode: 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, data: 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, data: 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, data: 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, data: 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 | */ |
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 | */ |
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 | */ |
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 |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | |