// SPDX-License-Identifier: GPL-2.0 #define USE_DVICHIP #ifdef USE_DVICHIP #include "ddk750_sii164.h" #include "ddk750_hwi2c.h" /* I2C Address of each SII164 chip */ #define SII164_I2C_ADDRESS 0x70 /* Define this definition to use hardware i2c. */ #define USE_HW_I2C #ifdef USE_HW_I2C #define i2cWriteReg sm750_hw_i2c_write_reg #define i2cReadReg sm750_hw_i2c_read_reg #else #define i2cWriteReg sm750_sw_i2c_write_reg #define i2cReadReg sm750_sw_i2c_read_reg #endif /* SII164 Vendor and Device ID */ #define SII164_VENDOR_ID 0x0001 #define SII164_DEVICE_ID 0x0006 #ifdef SII164_FULL_FUNCTIONS /* Name of the DVI Controller chip */ static char *gDviCtrlChipName = "Silicon Image SiI 164"; #endif /* * sii164_get_vendor_id * This function gets the vendor ID of the DVI controller chip. * * Output: * Vendor ID */ unsigned short sii164_get_vendor_id(void) { unsigned short vendorID; vendorID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_HIGH) << 8) | (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_LOW); return vendorID; } /* * sii164GetDeviceID * This function gets the device ID of the DVI controller chip. * * Output: * Device ID */ unsigned short sii164GetDeviceID(void) { unsigned short deviceID; deviceID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_HIGH) << 8) | (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_LOW); return deviceID; } /* * DVI.C will handle all SiI164 chip stuffs and try its best to make code * minimal and useful */ /* * sii164_init_chip * This function initialize and detect the DVI controller chip. * * Input: * edge_select - Edge Select: * 0 = Input data is falling edge latched (falling * edge latched first in dual edge mode) * 1 = Input data is rising edge latched (rising * edge latched first in dual edge mode) * bus_select - Input Bus Select: * 0 = Input data bus is 12-bits wide * 1 = Input data bus is 24-bits wide * dual_edge_clk_select - Dual Edge Clock Select * 0 = Input data is single edge latched * 1 = Input data is dual edge latched * hsync_enable - Horizontal Sync Enable: * 0 = HSYNC input is transmitted as fixed LOW * 1 = HSYNC input is transmitted as is * vsync_enable - Vertical Sync Enable: * 0 = VSYNC input is transmitted as fixed LOW * 1 = VSYNC input is transmitted as is * deskew_enable - De-skewing Enable: * 0 = De-skew disabled * 1 = De-skew enabled * deskew_setting - De-skewing Setting (increment of 260psec) * 0 = 1 step --> minimum setup / maximum hold * 1 = 2 step * 2 = 3 step * 3 = 4 step * 4 = 5 step * 5 = 6 step * 6 = 7 step * 7 = 8 step --> maximum setup / minimum hold * continuous_sync_enable- SYNC Continuous: * 0 = Disable * 1 = Enable * pll_filter_enable - PLL Filter Enable * 0 = Disable PLL Filter * 1 = Enable PLL Filter * pll_filter_value - PLL Filter characteristics: * 0~7 (recommended value is 4) * * Output: * 0 - Success * -1 - Fail. */ long 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) { unsigned char config; /* Initialize the i2c bus */ #ifdef USE_HW_I2C /* Use fast mode. */ sm750_hw_i2c_init(1); #else sm750_sw_i2c_init(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA); #endif /* Check if SII164 Chip exists */ if ((sii164_get_vendor_id() == SII164_VENDOR_ID) && (sii164GetDeviceID() == SII164_DEVICE_ID)) { /* * Initialize SII164 controller chip. */ /* Select the edge */ if (edge_select == 0) config = SII164_CONFIGURATION_LATCH_FALLING; else config = SII164_CONFIGURATION_LATCH_RISING; /* Select bus wide */ if (bus_select == 0) config |= SII164_CONFIGURATION_BUS_12BITS; else config |= SII164_CONFIGURATION_BUS_24BITS; /* Select Dual/Single Edge Clock */ if (dual_edge_clk_select == 0) config |= SII164_CONFIGURATION_CLOCK_SINGLE; else config |= SII164_CONFIGURATION_CLOCK_DUAL; /* Select HSync Enable */ if (hsync_enable == 0) config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW; else config |= SII164_CONFIGURATION_HSYNC_AS_IS; /* Select VSync Enable */ if (vsync_enable == 0) config |= SII164_CONFIGURATION_VSYNC_FORCE_LOW; else config |= SII164_CONFIGURATION_VSYNC_AS_IS; i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); /* * De-skew enabled with default 111b value. * This fixes some artifacts problem in some mode on board 2.2. * Somehow this fix does not affect board 2.1. */ if (deskew_enable == 0) config = SII164_DESKEW_DISABLE; else config = SII164_DESKEW_ENABLE; switch (deskew_setting) { case 0: config |= SII164_DESKEW_1_STEP; break; case 1: config |= SII164_DESKEW_2_STEP; break; case 2: config |= SII164_DESKEW_3_STEP; break; case 3: config |= SII164_DESKEW_4_STEP; break; case 4: config |= SII164_DESKEW_5_STEP; break; case 5: config |= SII164_DESKEW_6_STEP; break; case 6: config |= SII164_DESKEW_7_STEP; break; case 7: config |= SII164_DESKEW_8_STEP; break; } i2cWriteReg(SII164_I2C_ADDRESS, SII164_DESKEW, config); /* Enable/Disable Continuous Sync. */ if (continuous_sync_enable == 0) config = SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE; else config = SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE; /* Enable/Disable PLL Filter */ if (pll_filter_enable == 0) config |= SII164_PLL_FILTER_DISABLE; else config |= SII164_PLL_FILTER_ENABLE; /* Set the PLL Filter value */ config |= ((pll_filter_value & 0x07) << 1); i2cWriteReg(SII164_I2C_ADDRESS, SII164_PLL, config); /* Recover from Power Down and enable output. */ config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); config |= SII164_CONFIGURATION_POWER_NORMAL; i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); return 0; } /* Return -1 if initialization fails. */ return -1; } /* below sii164 function is not necessary */ #ifdef SII164_FULL_FUNCTIONS /* * sii164ResetChip * This function resets the DVI Controller Chip. */ void sii164ResetChip(void) { /* Power down */ sii164SetPower(0); sii164SetPower(1); } /* * sii164GetChipString * This function returns a char string name of the current DVI Controller * chip. * * It's convenient for application need to display the chip name. */ char *sii164GetChipString(void) { return gDviCtrlChipName; } /* * sii164SetPower * This function sets the power configuration of the DVI Controller Chip. * * Input: * powerUp - Flag to set the power down or up */ void sii164SetPower(unsigned char powerUp) { unsigned char config; config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); if (powerUp == 1) { /* Power up the chip */ config &= ~SII164_CONFIGURATION_POWER_MASK; config |= SII164_CONFIGURATION_POWER_NORMAL; i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); } else { /* Power down the chip */ config &= ~SII164_CONFIGURATION_POWER_MASK; config |= SII164_CONFIGURATION_POWER_DOWN; i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); } } /* * sii164SelectHotPlugDetectionMode * This function selects the mode of the hot plug detection. */ static void sii164SelectHotPlugDetectionMode(enum sii164_hot_plug_mode hotPlugMode) { unsigned char detectReg; detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & ~SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG; switch (hotPlugMode) { case SII164_HOTPLUG_DISABLE: detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH; break; case SII164_HOTPLUG_USE_MDI: detectReg &= ~SII164_DETECT_INTERRUPT_MASK; detectReg |= SII164_DETECT_INTERRUPT_BY_HTPLG_PIN; detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI; break; case SII164_HOTPLUG_USE_RSEN: detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN; break; case SII164_HOTPLUG_USE_HTPLG: detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG; break; } i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg); } /* * sii164EnableHotPlugDetection * This function enables the Hot Plug detection. * * enableHotPlug - Enable (=1) / disable (=0) Hot Plug detection */ void sii164EnableHotPlugDetection(unsigned char enableHotPlug) { unsigned char detectReg; detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); /* Depending on each DVI controller, need to enable the hot plug based * on each individual chip design. */ if (enableHotPlug != 0) sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_USE_MDI); else sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_DISABLE); } /* * sii164IsConnected * Check if the DVI Monitor is connected. * * Output: * 0 - Not Connected * 1 - Connected */ unsigned char sii164IsConnected(void) { unsigned char hotPlugValue; hotPlugValue = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & SII164_DETECT_HOT_PLUG_STATUS_MASK; if (hotPlugValue == SII164_DETECT_HOT_PLUG_STATUS_ON) return 1; else return 0; } /* * sii164CheckInterrupt * Checks if interrupt has occurred. * * Output: * 0 - No interrupt * 1 - Interrupt occurs */ unsigned char sii164CheckInterrupt(void) { unsigned char detectReg; detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & SII164_DETECT_MONITOR_STATE_MASK; if (detectReg == SII164_DETECT_MONITOR_STATE_CHANGE) return 1; else return 0; } /* * sii164ClearInterrupt * Clear the hot plug interrupt. */ void sii164ClearInterrupt(void) { unsigned char detectReg; /* Clear the MDI interrupt */ detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg | SII164_DETECT_MONITOR_STATE_CLEAR); } #endif #endif