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