The iCLKIP clock is used to drive the VGA pixel clock on the PCH. In order to do so, it must be programmed to properly do the clock ticks according to the divisor, phase direction, phase increments and a special auxiliary divisor for 20MHz clock. Those values can be programmed individually, by doing some math; or we could use a pre-defined table of values for each modeset. For speed and simplification, the idea was to just adopt the table of valid pixel clocks and select the matching iCLKIP values from there. As a possible idea for the future, it would be possible to add a fallback and calculate those values manually in case no match is found. But I don't think we'll encounter a mode not covered by those table, and VGA is pretty much going away in the future anyway. Signed-off-by: Eugeni Dodonov <eugeni.dodonov at intel.com> --- drivers/gpu/drm/i915/intel_display.c | 309 ++++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ac34457..bdc22f5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2958,6 +2958,312 @@ static const long hsw_ddi_buf_ctl_values[] = { DDI_BUF_EMP_800MV_3_5DB_HSW }; +/* Available pixel clock values */ +struct iclk_vga_clock { + u32 clock; + u16 auxdiv; + u16 divsel; + u16 phasedir; + u16 phaseinc; +}; + +static const struct iclk_vga_clock iclk_vga_clock_table[] = { + {20000, 1, 0x41, 0, 0x20}, /* 20000 ppm=0 */ + {21000, 0, 0x7E, 0, 0x25}, /* 20999 ppm=-53 */ + {21912, 0, 0x79, 0, 0x0E}, /* 21912 ppm=12 */ + {22000, 0, 0x78, 0, 0x2F}, /* 21999 ppm=-58 */ + {23000, 0, 0x73, 0, 0x19}, /* 23000 ppm=6 */ + {24000, 0, 0x6E, 0, 0x20}, /* 24000 ppm=0 */ + {25000, 0, 0x6A, 0, 0x00}, /* 25000 ppm=0 */ + {25175, 0, 0x69, 0, 0x10}, /* 25175 ppm=-7 */ + {25200, 0, 0x69, 0, 0x09}, /* 25201 ppm=21 */ + {26000, 0, 0x66, 1, 0x0A}, /* 26001 ppm=24 */ + {27000, 0, 0x62, 0, 0x00}, /* 27000 ppm=0 */ + {27027, 0, 0x62, 1, 0x06}, /* 27025 ppm=-62 */ + {27500, 0, 0x60, 0, 0x0C}, /* 27498 ppm=-58 */ + {28000, 0, 0x5E, 0, 0x1B}, /* 28002 ppm=70 */ + {28320, 0, 0x5D, 0, 0x16}, /* 28319 ppm=-50 */ + {28322, 0, 0x5D, 0, 0x15}, /* 28323 ppm=44 */ + {29000, 0, 0x5B, 0, 0x07}, /* 28998 ppm=-64 */ + {30000, 0, 0x58, 0, 0x00}, /* 30000 ppm=0 */ + {31000, 0, 0x55, 0, 0x06}, /* 31001 ppm=35 */ + {31500, 0, 0x54, 1, 0x12}, /* 31498 ppm=-53 */ + {32000, 0, 0x52, 0, 0x18}, /* 32000 ppm=0 */ + {32500, 0, 0x51, 0, 0x05}, /* 32500 ppm=-15 */ + {33000, 0, 0x50, 1, 0x0C}, /* 33002 ppm=70 */ + {34000, 0, 0x4D, 0, 0x1A}, /* 34002 ppm=70 */ + {35000, 0, 0x4B, 0, 0x09}, /* 35001 ppm=29 */ + {35500, 0, 0x4A, 0, 0x04}, /* 35497 ppm=-82 */ + {36000, 0, 0x49, 0, 0x00}, /* 36000 ppm=0 */ + {37000, 0, 0x47, 1, 0x02}, /* 37002 ppm=58 */ + {38000, 0, 0x45, 0, 0x03}, /* 38003 ppm=82 */ + {39000, 0, 0x43, 0, 0x0F}, /* 38998 ppm=-53 */ + {40000, 0, 0x41, 0, 0x20}, /* 40000 ppm=0 */ + {40500, 0, 0x41, 1, 0x15}, /* 40497 ppm=-79 */ + {40541, 0, 0x41, 1, 0x1A}, /* 40544 ppm=95 */ + {41000, 0, 0x40, 1, 0x09}, /* 40996 ppm=-87 */ + {41540, 0, 0x3F, 0, 0x00}, /* 41538 ppm=-38 */ + {42000, 0, 0x3E, 0, 0x12}, /* 42003 ppm=70 */ + {43000, 0, 0x3D, 1, 0x0D}, /* 42996 ppm=-99 */ + {43163, 0, 0x3D, 1, 0x1D}, /* 43168 ppm=108 */ + {44000, 0, 0x3B, 0, 0x17}, /* 44003 ppm=70 */ + {44900, 0, 0x3A, 0, 0x09}, /* 44895 ppm=-117 */ + {45000, 0, 0x3A, 0, 0x00}, /* 45000 ppm=0 */ + {46000, 0, 0x39, 1, 0x13}, /* 45994 ppm=-128 */ + {47000, 0, 0x37, 0, 0x1D}, /* 46995 ppm=-110 */ + {48000, 0, 0x36, 0, 0x10}, /* 48000 ppm=0 */ + {49000, 0, 0x35, 0, 0x07}, /* 48993 ppm=-134 */ + {49500, 0, 0x35, 1, 0x1D}, /* 49499 ppm=-27 */ + {50000, 0, 0x34, 0, 0x00}, /* 50000 ppm=0 */ + {51000, 0, 0x33, 1, 0x04}, /* 51004 ppm=70 */ + {52000, 0, 0x32, 1, 0x05}, /* 52001 ppm=24 */ + {52406, 0, 0x32, 1, 0x1F}, /* 52411 ppm=101 */ + {53000, 0, 0x31, 1, 0x04}, /* 53006 ppm=116 */ + {54000, 0, 0x30, 0, 0x00}, /* 54000 ppm=0 */ + {54054, 0, 0x30, 1, 0x03}, /* 54051 ppm=-62 */ + {55000, 0, 0x2F, 0, 0x06}, /* 54997 ppm=-58 */ + {56000, 0, 0x2E, 0, 0x0E}, /* 55995 ppm=-93 */ + {56250, 0, 0x2E, 0, 0x00}, /* 56250 ppm=0 */ + {57000, 0, 0x2D, 0, 0x18}, /* 56992 ppm=-139 */ + {58000, 0, 0x2D, 1, 0x1D}, /* 58006 ppm=105 */ + {59000, 0, 0x2C, 1, 0x0F}, /* 58996 ppm=-64 */ + {60000, 0, 0x2B, 0, 0x00}, /* 60000 ppm=0 */ + {61000, 0, 0x2A, 0, 0x11}, /* 60995 ppm=-76 */ + {62000, 0, 0x2A, 1, 0x1D}, /* 62002 ppm=35 */ + {63000, 0, 0x29, 1, 0x09}, /* 62997 ppm=-53 */ + {64000, 0, 0x28, 0, 0x0C}, /* 64000 ppm=0 */ + {65000, 0, 0x28, 1, 0x1E}, /* 65011 ppm=174 */ + {66000, 0, 0x27, 1, 0x06}, /* 66005 ppm=70 */ + {66667, 0, 0x26, 0, 0x20}, /* 66667 ppm=-5 */ + {67000, 0, 0x26, 0, 0x13}, /* 67003 ppm=41 */ + {68000, 0, 0x26, 1, 0x13}, /* 68005 ppm=70 */ + {68179, 0, 0x26, 1, 0x19}, /* 68166 ppm=-196 */ + {69000, 0, 0x25, 0, 0x08}, /* 69010 ppm=139 */ + {70000, 0, 0x25, 1, 0x1B}, /* 69988 ppm=-174 */ + {71000, 0, 0x24, 0, 0x02}, /* 70994 ppm=-82 */ + {72000, 0, 0x23, 0, 0x20}, /* 72000 ppm=0 */ + {73000, 0, 0x23, 1, 0x01}, /* 73004 ppm=53 */ + {74000, 0, 0x22, 0, 0x1F}, /* 74004 ppm=58 */ + {74175, 0, 0x22, 0, 0x1A}, /* 74163 ppm=-161 */ + {74250, 0, 0x22, 0, 0x17}, /* 74259 ppm=118 */ + {74481, 0, 0x22, 0, 0x10}, /* 74483 ppm=24 */ + {75000, 0, 0x22, 0, 0x00}, /* 75000 ppm=0 */ + {76000, 0, 0x22, 1, 0x1E}, /* 75989 ppm=-139 */ + {77000, 0, 0x21, 0, 0x04}, /* 77005 ppm=70 */ + {78000, 0, 0x21, 1, 0x19}, /* 78014 ppm=174 */ + {78750, 0, 0x20, 0, 0x12}, /* 78760 ppm=131 */ + {79000, 0, 0x20, 0, 0x0B}, /* 79012 ppm=157 */ + {80000, 0, 0x20, 1, 0x10}, /* 80000 ppm=0 */ + {81000, 0, 0x1F, 0, 0x15}, /* 81013 ppm=157 */ + {81081, 0, 0x1F, 0, 0x13}, /* 81089 ppm=95 */ + {81624, 0, 0x1F, 0, 0x05}, /* 81625 ppm=12 */ + {82000, 0, 0x1F, 1, 0x05}, /* 82012 ppm=151 */ + {83000, 0, 0x1F, 1, 0x1E}, /* 82997 ppm=-35 */ + {83950, 0, 0x1E, 0, 0x0A}, /* 83965 ppm=179 */ + {84000, 0, 0x1E, 0, 0x09}, /* 84006 ppm=70 */ + {85000, 0, 0x1E, 1, 0x0F}, /* 84998 ppm=-29 */ + {86000, 0, 0x1D, 0, 0x19}, /* 86013 ppm=151 */ + {87000, 0, 0x1D, 0, 0x02}, /* 87009 ppm=105 */ + {88000, 0, 0x1D, 1, 0x14}, /* 87984 ppm=-186 */ + {89000, 0, 0x1C, 0, 0x16}, /* 88980 ppm=-220 */ + {90000, 0, 0x1C, 0, 0x00}, /* 90000 ppm=0 */ + {91000, 0, 0x1C, 1, 0x15}, /* 90995 ppm=-53 */ + {92000, 0, 0x1B, 0, 0x16}, /* 92013 ppm=139 */ + {93000, 0, 0x1B, 0, 0x02}, /* 93003 ppm=35 */ + {94000, 0, 0x1B, 1, 0x12}, /* 94015 ppm=163 */ + {94500, 0, 0x1B, 1, 0x1B}, /* 94478 ppm=-235 */ + {95000, 0, 0x1A, 0, 0x1B}, /* 94997 ppm=-29 */ + {95654, 0, 0x1A, 0, 0x0F}, /* 95628 ppm=-271 */ + {96000, 0, 0x1A, 0, 0x08}, /* 96000 ppm=0 */ + {97000, 0, 0x1A, 1, 0x0B}, /* 97024 ppm=249 */ + {98000, 0, 0x1A, 1, 0x1D}, /* 98015 ppm=151 */ + {99000, 0, 0x19, 0, 0x11}, /* 99026 ppm=261 */ + {100000, 0, 0x19, 0, 0x00}, /* 100000 ppm=0 */ + {101000, 0, 0x19, 1, 0x11}, /* 100994 ppm=-64 */ + {102000, 0, 0x18, 0, 0x1E}, /* 102007 ppm=70 */ + {103000, 0, 0x18, 0, 0x0E}, /* 102980 ppm=-197 */ + {104000, 0, 0x18, 1, 0x02}, /* 103971 ppm=-278 */ + {105000, 0, 0x18, 1, 0x12}, /* 104982 ppm=-174 */ + {106000, 0, 0x17, 0, 0x1E}, /* 106012 ppm=116 */ + {107000, 0, 0x17, 0, 0x0F}, /* 106997 ppm=-29 */ + {107214, 0, 0x17, 0, 0x0C}, /* 107196 ppm=-168 */ + {108000, 0, 0x17, 0, 0x00}, /* 108000 ppm=0 */ + {109000, 0, 0x17, 1, 0x0F}, /* 109022 ppm=203 */ + {110000, 0, 0x17, 1, 0x1D}, /* 109994 ppm=-58 */ + {110013, 0, 0x17, 1, 0x1D}, /* 109994 ppm=-177 */ + {111000, 0, 0x16, 0, 0x15}, /* 110983 ppm=-157 */ + {111263, 0, 0x16, 0, 0x11}, /* 111269 ppm=55 */ + {111375, 0, 0x16, 0, 0x10}, /* 111340 ppm=-313 */ + {112000, 0, 0x16, 0, 0x07}, /* 111990 ppm=-93 */ + {113000, 0, 0x16, 1, 0x07}, /* 113015 ppm=134 */ + {113309, 0, 0x16, 1, 0x0B}, /* 113311 ppm=22 */ + {113100, 0, 0x16, 1, 0x08}, /* 113089 ppm=-98 */ + {114000, 0, 0x16, 1, 0x14}, /* 113984 ppm=-139 */ + {115000, 0, 0x15, 0, 0x1F}, /* 114970 ppm=-261 */ + {116000, 0, 0x15, 0, 0x12}, /* 115973 ppm=-232 */ + {117000, 0, 0x15, 0, 0x05}, /* 116994 ppm=-53 */ + {118000, 0, 0x15, 1, 0x08}, /* 118033 ppm=278 */ + {119000, 0, 0x15, 1, 0x14}, /* 119008 ppm=70 */ + {119651, 0, 0x15, 1, 0x1C}, /* 119668 ppm=139 */ + {120000, 0, 0x14, 0, 0x20}, /* 120000 ppm=0 */ + {121000, 0, 0x14, 0, 0x14}, /* 121008 ppm=70 */ + {122000, 0, 0x14, 0, 0x08}, /* 122034 ppm=278 */ + {122614, 0, 0x14, 0, 0x01}, /* 122640 ppm=214 */ + {123000, 0, 0x14, 1, 0x03}, /* 122989 ppm=-87 */ + {123379, 0, 0x14, 1, 0x07}, /* 123340 ppm=-313 */ + {124000, 0, 0x14, 1, 0x0E}, /* 123960 ppm=-324 */ + {125000, 0, 0x14, 1, 0x1A}, /* 125036 ppm=290 */ + {126000, 0, 0x13, 0, 0x1B}, /* 126039 ppm=313 */ + {127000, 0, 0x13, 0, 0x11}, /* 126965 ppm=-272 */ + {128000, 0, 0x13, 0, 0x06}, /* 128000 ppm=0 */ + {129000, 0, 0x13, 1, 0x04}, /* 128955 ppm=-348 */ + {129859, 0, 0x13, 1, 0x0D}, /* 129827 ppm=-245 */ + {130000, 0, 0x13, 1, 0x0F}, /* 130023 ppm=174 */ + {131000, 0, 0x13, 1, 0x19}, /* 131008 ppm=64 */ + {131850, 0, 0x12, 0, 0x1F}, /* 131808 ppm=-321 */ + {132000, 0, 0x12, 0, 0x1D}, /* 132009 ppm=70 */ + {133000, 0, 0x12, 0, 0x13}, /* 133025 ppm=192 */ + {133330, 0, 0x12, 0, 0x10}, /* 133333 ppm=26 */ + {134000, 0, 0x12, 0, 0x0A}, /* 133953 ppm=-348 */ + {135000, 0, 0x12, 0, 0x00}, /* 135000 ppm=0 */ + {136000, 0, 0x12, 1, 0x09}, /* 135956 ppm=-324 */ + {137000, 0, 0x12, 1, 0x13}, /* 137034 ppm=249 */ + {138000, 0, 0x12, 1, 0x1C}, /* 138019 ppm=139 */ + {139000, 0, 0x11, 0, 0x1B}, /* 139019 ppm=134 */ + {139050, 0, 0x11, 0, 0x1B}, /* 139019 ppm=-227 */ + {139054, 0, 0x11, 0, 0x1B}, /* 139019 ppm=-256 */ + {140000, 0, 0x11, 0, 0x12}, /* 140032 ppm=232 */ + {141000, 0, 0x11, 0, 0x0A}, /* 140946 ppm=-382 */ + {142000, 0, 0x11, 0, 0x01}, /* 141988 ppm=-82 */ + {143000, 0, 0x11, 1, 0x08}, /* 143046 ppm=325 */ + {143472, 0, 0x11, 1, 0x0C}, /* 143522 ppm=346 */ + {144000, 0, 0x11, 1, 0x10}, /* 144000 ppm=0 */ + {145000, 0, 0x11, 1, 0x18}, /* 144966 ppm=-232 */ + {146000, 0, 0x10, 0, 0x20}, /* 145946 ppm=-371 */ + {147000, 0, 0x10, 0, 0x18}, /* 146939 ppm=-417 */ + {147891, 0, 0x10, 0, 0x10}, /* 147945 ppm=367 */ + {148000, 0, 0x10, 0, 0x10}, /* 147945 ppm=-371 */ + {148350, 0, 0x10, 0, 0x0D}, /* 148326 ppm=-161 */ + {148500, 0, 0x10, 0, 0x0C}, /* 148454 ppm=-313 */ + {149000, 0, 0x10, 0, 0x08}, /* 148966 ppm=-232 */ + {150000, 0, 0x10, 0, 0x00}, /* 150000 ppm=0 */ + {151000, 0, 0x10, 1, 0x08}, /* 151049 ppm=325 */ + {152000, 0, 0x10, 1, 0x0F}, /* 151979 ppm=-139 */ + {152280, 0, 0x10, 1, 0x11}, /* 152247 ppm=-219 */ + {153000, 0, 0x10, 1, 0x17}, /* 153056 ppm=365 */ + {154000, 0, 0x10, 1, 0x1E}, /* 154011 ppm=70 */ + {155000, 0, 0x0F, 0, 0x1B}, /* 154978 ppm=-145 */ + {156000, 0, 0x0F, 0, 0x14}, /* 155957 ppm=-278 */ + {157000, 0, 0x0F, 0, 0x0D}, /* 156948 ppm=-330 */ + {157500, 0, 0x0F, 0, 0x09}, /* 157521 ppm=131 */ + {158000, 0, 0x0F, 0, 0x06}, /* 157952 ppm=-301 */ + {159000, 0, 0x0F, 1, 0x01}, /* 158970 ppm=-191 */ + {160000, 0, 0x0F, 1, 0x08}, /* 160000 ppm=0 */ + {161000, 0, 0x0F, 1, 0x0F}, /* 161044 ppm=273 */ + {162000, 0, 0x0F, 1, 0x15}, /* 161949 ppm=-313 */ + {163000, 0, 0x0F, 1, 0x1C}, /* 163019 ppm=116 */ + {164000, 0, 0x0E, 0, 0x1E}, /* 163947 ppm=-324 */ + {165000, 0, 0x0E, 0, 0x17}, /* 165043 ppm=261 */ + {166000, 0, 0x0E, 0, 0x11}, /* 165994 ppm=-35 */ + {167000, 0, 0x0E, 0, 0x0B}, /* 166957 ppm=-261 */ + {168000, 0, 0x0E, 0, 0x05}, /* 167930 ppm=-417 */ + {169000, 0, 0x0E, 1, 0x02}, /* 169080 ppm=475 */ + {169128, 0, 0x0E, 1, 0x02}, /* 169080 ppm=-283 */ + {170000, 0, 0x0E, 1, 0x08}, /* 170079 ppm=464 */ + {171000, 0, 0x0E, 1, 0x0D}, /* 170920 ppm=-469 */ + {172000, 0, 0x0E, 1, 0x13}, /* 171940 ppm=-348 */ + {172800, 0, 0x0E, 1, 0x18}, /* 172800 ppm=0 */ + {173000, 0, 0x0E, 1, 0x19}, /* 172973 ppm=-157 */ + {174000, 0, 0x0E, 1, 0x1F}, /* 174018 ppm=105 */ + {174787, 0, 0x0D, 0, 0x1D}, /* 174722 ppm=-373 */ + {175000, 0, 0x0D, 0, 0x1B}, /* 175076 ppm=435 */ + {175500, 0, 0x0D, 0, 0x19}, /* 175431 ppm=-391 */ + {176000, 0, 0x0D, 0, 0x16}, /* 175967 ppm=-186 */ + {177000, 0, 0x0D, 0, 0x10}, /* 177049 ppm=278 */ + {178000, 0, 0x0D, 0, 0x0B}, /* 177961 ppm=-220 */ + {179000, 0, 0x0D, 0, 0x05}, /* 179067 ppm=377 */ + {180000, 0, 0x0D, 0, 0x00}, /* 180000 ppm=0 */ +}; + +/* Program iCLKIP clock to the desired frequency */ +static void lpt_program_iclkip(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 auxdiv=0, divsel=0, phasedir=0, phaseinc=0, valid=0; + u32 temp, i; + + /* Ungate pixel clock */ + I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE); + + /* Disable SSCCTL */ + intel_sbi_write(dev_priv, SBI_SSCCTL6, + intel_sbi_read(dev_priv, SBI_SSCCTL6) | + SBI_SSCCTL_DISABLE); + + /* Calculating clock values for iCLKIP */ + for (i=0; i < ARRAY_SIZE(iclk_vga_clock_table); i++) { + if (crtc->mode.clock == iclk_vga_clock_table[i].clock) { + DRM_INFO("Found clock settings for %dKHz refresh rate\n", + crtc->mode.clock); + + auxdiv = iclk_vga_clock_table[i].auxdiv; + divsel = iclk_vga_clock_table[i].divsel; + phasedir = iclk_vga_clock_table[i].phasedir; + phaseinc = iclk_vga_clock_table[i].phaseinc; + + valid = 1; + + break; + } + } + + if (!valid) { + DRM_ERROR("Unable to find iCLKIP clock settings for %dKHz refresh rate\n", + crtc->mode.clock); + return; + } + + /* Program SSCDIVINTPHASE6 with values which HW team uses */ + DRM_DEBUG("Programming SSCDIVINTPHASE for %dKHz: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n", + crtc->mode.clock, + auxdiv, + divsel, + phasedir, + phaseinc); + + /* Program SSCDIVINTPHASE6 */ + temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6); + temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK; + temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel); + temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK; + temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc); + temp |= SBI_SSCDIVINTPHASE_DIR(phasedir); + temp |= SBI_SSCDIVINTPHASE_PROPAGATE; + + intel_sbi_write(dev_priv, + SBI_SSCDIVINTPHASE6, + temp); + + /* Program SSCAUXDIV */ + intel_sbi_write(dev_priv, + SBI_SSCAUXDIV6, + intel_sbi_read(dev_priv, SBI_SSCAUXDIV6) | + SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv)); + + + /* Enable modulator and associated divider */ + intel_sbi_write(dev_priv, SBI_SSCCTL6, + intel_sbi_read(dev_priv, SBI_SSCCTL6) & + ~SBI_SSCCTL_DISABLE); + + /* Wait for initialization time */ + udelay(50); + + /* Gate pixel clock */ + I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE); +} + /* Link training for HSW parts */ static void hsw_fdi_link_train(struct drm_crtc *crtc) @@ -3386,6 +3692,9 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) temp |= (TRANSC_DPLL_ENABLE | transc_sel); } I915_WRITE(PCH_DPLL_SEL, temp); + } else if (HAS_PCH_LPT(dev)) { + /* Program iCLKIP */ + lpt_program_iclkip(crtc); } /* set transcoder timing, panel must allow it */ -- 1.7.10