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