84,25 → 84,17 |
* in either FDI or DP modes only, as HDMI connections will work with both |
* of those |
*/ |
static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, |
bool use_fdi_mode) |
static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 reg; |
int i; |
const u32 *ddi_translations = ((use_fdi_mode) ? |
const u32 *ddi_translations = (port == PORT_E) ? |
hsw_ddi_translations_fdi : |
hsw_ddi_translations_dp); |
hsw_ddi_translations_dp; |
|
DRM_DEBUG_DRIVER("Initializing DDI buffers for port %c in %s mode\n", |
port_name(port), |
use_fdi_mode ? "FDI" : "DP"); |
|
WARN((use_fdi_mode && (port != PORT_E)), |
"Programming port %c in FDI mode, this probably will not work.\n", |
port_name(port)); |
|
for (i=0, reg=DDI_BUF_TRANS(port); i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) { |
for (i = 0, reg = DDI_BUF_TRANS(port); |
i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) { |
I915_WRITE(reg, ddi_translations[i]); |
reg += 4; |
} |
118,14 → 110,8 |
if (!HAS_DDI(dev)) |
return; |
|
for (port = PORT_A; port < PORT_E; port++) |
intel_prepare_ddi_buffers(dev, port, false); |
|
/* DDI E is the suggested one to work in FDI mode, so program is as such |
* by default. It will have to be re-programmed in case a digital DP |
* output will be detected on it |
*/ |
intel_prepare_ddi_buffers(dev, PORT_E, true); |
for (port = PORT_A; port <= PORT_E; port++) |
intel_prepare_ddi_buffers(dev, port); |
} |
|
static const long hsw_ddi_buf_ctl_values[] = { |
174,6 → 160,8 |
* mode set "sequence for CRT port" document: |
* - TP1 to TP2 time with the default value |
* - FDI delay to 90h |
* |
* WaFDIAutoLinkSetTimingOverrride:hsw |
*/ |
I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) | |
FDI_RX_PWRDN_LANE0_VAL(2) | |
181,7 → 169,8 |
|
/* Enable the PCH Receiver FDI PLL */ |
rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | |
FDI_RX_PLL_ENABLE | ((intel_crtc->fdi_lanes - 1) << 19); |
FDI_RX_PLL_ENABLE | |
FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); |
I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); |
POSTING_READ(_FDI_RXA_CTL); |
udelay(220); |
209,7 → 198,7 |
* port reversal bit */ |
I915_WRITE(DDI_BUF_CTL(PORT_E), |
DDI_BUF_CTL_ENABLE | |
((intel_crtc->fdi_lanes - 1) << 1) | |
((intel_crtc->config.fdi_lanes - 1) << 1) | |
hsw_ddi_buf_ctl_values[i / 2]); |
POSTING_READ(DDI_BUF_CTL(PORT_E)); |
|
278,444 → 267,40 |
DRM_ERROR("FDI link training failed!\n"); |
} |
|
/* WRPLL clock dividers */ |
struct wrpll_tmds_clock { |
u32 clock; |
u16 p; /* Post divider */ |
u16 n2; /* Feedback divider */ |
u16 r2; /* Reference divider */ |
}; |
|
/* Table of matching values for WRPLL clocks programming for each frequency. |
* The code assumes this table is sorted. */ |
static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = { |
{19750, 38, 25, 18}, |
{20000, 48, 32, 18}, |
{21000, 36, 21, 15}, |
{21912, 42, 29, 17}, |
{22000, 36, 22, 15}, |
{23000, 36, 23, 15}, |
{23500, 40, 40, 23}, |
{23750, 26, 16, 14}, |
{24000, 36, 24, 15}, |
{25000, 36, 25, 15}, |
{25175, 26, 40, 33}, |
{25200, 30, 21, 15}, |
{26000, 36, 26, 15}, |
{27000, 30, 21, 14}, |
{27027, 18, 100, 111}, |
{27500, 30, 29, 19}, |
{28000, 34, 30, 17}, |
{28320, 26, 30, 22}, |
{28322, 32, 42, 25}, |
{28750, 24, 23, 18}, |
{29000, 30, 29, 18}, |
{29750, 32, 30, 17}, |
{30000, 30, 25, 15}, |
{30750, 30, 41, 24}, |
{31000, 30, 31, 18}, |
{31500, 30, 28, 16}, |
{32000, 30, 32, 18}, |
{32500, 28, 32, 19}, |
{33000, 24, 22, 15}, |
{34000, 28, 30, 17}, |
{35000, 26, 32, 19}, |
{35500, 24, 30, 19}, |
{36000, 26, 26, 15}, |
{36750, 26, 46, 26}, |
{37000, 24, 23, 14}, |
{37762, 22, 40, 26}, |
{37800, 20, 21, 15}, |
{38000, 24, 27, 16}, |
{38250, 24, 34, 20}, |
{39000, 24, 26, 15}, |
{40000, 24, 32, 18}, |
{40500, 20, 21, 14}, |
{40541, 22, 147, 89}, |
{40750, 18, 19, 14}, |
{41000, 16, 17, 14}, |
{41500, 22, 44, 26}, |
{41540, 22, 44, 26}, |
{42000, 18, 21, 15}, |
{42500, 22, 45, 26}, |
{43000, 20, 43, 27}, |
{43163, 20, 24, 15}, |
{44000, 18, 22, 15}, |
{44900, 20, 108, 65}, |
{45000, 20, 25, 15}, |
{45250, 20, 52, 31}, |
{46000, 18, 23, 15}, |
{46750, 20, 45, 26}, |
{47000, 20, 40, 23}, |
{48000, 18, 24, 15}, |
{49000, 18, 49, 30}, |
{49500, 16, 22, 15}, |
{50000, 18, 25, 15}, |
{50500, 18, 32, 19}, |
{51000, 18, 34, 20}, |
{52000, 18, 26, 15}, |
{52406, 14, 34, 25}, |
{53000, 16, 22, 14}, |
{54000, 16, 24, 15}, |
{54054, 16, 173, 108}, |
{54500, 14, 24, 17}, |
{55000, 12, 22, 18}, |
{56000, 14, 45, 31}, |
{56250, 16, 25, 15}, |
{56750, 14, 25, 17}, |
{57000, 16, 27, 16}, |
{58000, 16, 43, 25}, |
{58250, 16, 38, 22}, |
{58750, 16, 40, 23}, |
{59000, 14, 26, 17}, |
{59341, 14, 40, 26}, |
{59400, 16, 44, 25}, |
{60000, 16, 32, 18}, |
{60500, 12, 39, 29}, |
{61000, 14, 49, 31}, |
{62000, 14, 37, 23}, |
{62250, 14, 42, 26}, |
{63000, 12, 21, 15}, |
{63500, 14, 28, 17}, |
{64000, 12, 27, 19}, |
{65000, 14, 32, 19}, |
{65250, 12, 29, 20}, |
{65500, 12, 32, 22}, |
{66000, 12, 22, 15}, |
{66667, 14, 38, 22}, |
{66750, 10, 21, 17}, |
{67000, 14, 33, 19}, |
{67750, 14, 58, 33}, |
{68000, 14, 30, 17}, |
{68179, 14, 46, 26}, |
{68250, 14, 46, 26}, |
{69000, 12, 23, 15}, |
{70000, 12, 28, 18}, |
{71000, 12, 30, 19}, |
{72000, 12, 24, 15}, |
{73000, 10, 23, 17}, |
{74000, 12, 23, 14}, |
{74176, 8, 100, 91}, |
{74250, 10, 22, 16}, |
{74481, 12, 43, 26}, |
{74500, 10, 29, 21}, |
{75000, 12, 25, 15}, |
{75250, 10, 39, 28}, |
{76000, 12, 27, 16}, |
{77000, 12, 53, 31}, |
{78000, 12, 26, 15}, |
{78750, 12, 28, 16}, |
{79000, 10, 38, 26}, |
{79500, 10, 28, 19}, |
{80000, 12, 32, 18}, |
{81000, 10, 21, 14}, |
{81081, 6, 100, 111}, |
{81624, 8, 29, 24}, |
{82000, 8, 17, 14}, |
{83000, 10, 40, 26}, |
{83950, 10, 28, 18}, |
{84000, 10, 28, 18}, |
{84750, 6, 16, 17}, |
{85000, 6, 17, 18}, |
{85250, 10, 30, 19}, |
{85750, 10, 27, 17}, |
{86000, 10, 43, 27}, |
{87000, 10, 29, 18}, |
{88000, 10, 44, 27}, |
{88500, 10, 41, 25}, |
{89000, 10, 28, 17}, |
{89012, 6, 90, 91}, |
{89100, 10, 33, 20}, |
{90000, 10, 25, 15}, |
{91000, 10, 32, 19}, |
{92000, 10, 46, 27}, |
{93000, 10, 31, 18}, |
{94000, 10, 40, 23}, |
{94500, 10, 28, 16}, |
{95000, 10, 44, 25}, |
{95654, 10, 39, 22}, |
{95750, 10, 39, 22}, |
{96000, 10, 32, 18}, |
{97000, 8, 23, 16}, |
{97750, 8, 42, 29}, |
{98000, 8, 45, 31}, |
{99000, 8, 22, 15}, |
{99750, 8, 34, 23}, |
{100000, 6, 20, 18}, |
{100500, 6, 19, 17}, |
{101000, 6, 37, 33}, |
{101250, 8, 21, 14}, |
{102000, 6, 17, 15}, |
{102250, 6, 25, 22}, |
{103000, 8, 29, 19}, |
{104000, 8, 37, 24}, |
{105000, 8, 28, 18}, |
{106000, 8, 22, 14}, |
{107000, 8, 46, 29}, |
{107214, 8, 27, 17}, |
{108000, 8, 24, 15}, |
{108108, 8, 173, 108}, |
{109000, 6, 23, 19}, |
{110000, 6, 22, 18}, |
{110013, 6, 22, 18}, |
{110250, 8, 49, 30}, |
{110500, 8, 36, 22}, |
{111000, 8, 23, 14}, |
{111264, 8, 150, 91}, |
{111375, 8, 33, 20}, |
{112000, 8, 63, 38}, |
{112500, 8, 25, 15}, |
{113100, 8, 57, 34}, |
{113309, 8, 42, 25}, |
{114000, 8, 27, 16}, |
{115000, 6, 23, 18}, |
{116000, 8, 43, 25}, |
{117000, 8, 26, 15}, |
{117500, 8, 40, 23}, |
{118000, 6, 38, 29}, |
{119000, 8, 30, 17}, |
{119500, 8, 46, 26}, |
{119651, 8, 39, 22}, |
{120000, 8, 32, 18}, |
{121000, 6, 39, 29}, |
{121250, 6, 31, 23}, |
{121750, 6, 23, 17}, |
{122000, 6, 42, 31}, |
{122614, 6, 30, 22}, |
{123000, 6, 41, 30}, |
{123379, 6, 37, 27}, |
{124000, 6, 51, 37}, |
{125000, 6, 25, 18}, |
{125250, 4, 13, 14}, |
{125750, 4, 27, 29}, |
{126000, 6, 21, 15}, |
{127000, 6, 24, 17}, |
{127250, 6, 41, 29}, |
{128000, 6, 27, 19}, |
{129000, 6, 43, 30}, |
{129859, 4, 25, 26}, |
{130000, 6, 26, 18}, |
{130250, 6, 42, 29}, |
{131000, 6, 32, 22}, |
{131500, 6, 38, 26}, |
{131850, 6, 41, 28}, |
{132000, 6, 22, 15}, |
{132750, 6, 28, 19}, |
{133000, 6, 34, 23}, |
{133330, 6, 37, 25}, |
{134000, 6, 61, 41}, |
{135000, 6, 21, 14}, |
{135250, 6, 167, 111}, |
{136000, 6, 62, 41}, |
{137000, 6, 35, 23}, |
{138000, 6, 23, 15}, |
{138500, 6, 40, 26}, |
{138750, 6, 37, 24}, |
{139000, 6, 34, 22}, |
{139050, 6, 34, 22}, |
{139054, 6, 34, 22}, |
{140000, 6, 28, 18}, |
{141000, 6, 36, 23}, |
{141500, 6, 22, 14}, |
{142000, 6, 30, 19}, |
{143000, 6, 27, 17}, |
{143472, 4, 17, 16}, |
{144000, 6, 24, 15}, |
{145000, 6, 29, 18}, |
{146000, 6, 47, 29}, |
{146250, 6, 26, 16}, |
{147000, 6, 49, 30}, |
{147891, 6, 23, 14}, |
{148000, 6, 23, 14}, |
{148250, 6, 28, 17}, |
{148352, 4, 100, 91}, |
{148500, 6, 33, 20}, |
{149000, 6, 48, 29}, |
{150000, 6, 25, 15}, |
{151000, 4, 19, 17}, |
{152000, 6, 27, 16}, |
{152280, 6, 44, 26}, |
{153000, 6, 34, 20}, |
{154000, 6, 53, 31}, |
{155000, 6, 31, 18}, |
{155250, 6, 50, 29}, |
{155750, 6, 45, 26}, |
{156000, 6, 26, 15}, |
{157000, 6, 61, 35}, |
{157500, 6, 28, 16}, |
{158000, 6, 65, 37}, |
{158250, 6, 44, 25}, |
{159000, 6, 53, 30}, |
{159500, 6, 39, 22}, |
{160000, 6, 32, 18}, |
{161000, 4, 31, 26}, |
{162000, 4, 18, 15}, |
{162162, 4, 131, 109}, |
{162500, 4, 53, 44}, |
{163000, 4, 29, 24}, |
{164000, 4, 17, 14}, |
{165000, 4, 22, 18}, |
{166000, 4, 32, 26}, |
{167000, 4, 26, 21}, |
{168000, 4, 46, 37}, |
{169000, 4, 104, 83}, |
{169128, 4, 64, 51}, |
{169500, 4, 39, 31}, |
{170000, 4, 34, 27}, |
{171000, 4, 19, 15}, |
{172000, 4, 51, 40}, |
{172750, 4, 32, 25}, |
{172800, 4, 32, 25}, |
{173000, 4, 41, 32}, |
{174000, 4, 49, 38}, |
{174787, 4, 22, 17}, |
{175000, 4, 35, 27}, |
{176000, 4, 30, 23}, |
{177000, 4, 38, 29}, |
{178000, 4, 29, 22}, |
{178500, 4, 37, 28}, |
{179000, 4, 53, 40}, |
{179500, 4, 73, 55}, |
{180000, 4, 20, 15}, |
{181000, 4, 55, 41}, |
{182000, 4, 31, 23}, |
{183000, 4, 42, 31}, |
{184000, 4, 30, 22}, |
{184750, 4, 26, 19}, |
{185000, 4, 37, 27}, |
{186000, 4, 51, 37}, |
{187000, 4, 36, 26}, |
{188000, 4, 32, 23}, |
{189000, 4, 21, 15}, |
{190000, 4, 38, 27}, |
{190960, 4, 41, 29}, |
{191000, 4, 41, 29}, |
{192000, 4, 27, 19}, |
{192250, 4, 37, 26}, |
{193000, 4, 20, 14}, |
{193250, 4, 53, 37}, |
{194000, 4, 23, 16}, |
{194208, 4, 23, 16}, |
{195000, 4, 26, 18}, |
{196000, 4, 45, 31}, |
{197000, 4, 35, 24}, |
{197750, 4, 41, 28}, |
{198000, 4, 22, 15}, |
{198500, 4, 25, 17}, |
{199000, 4, 28, 19}, |
{200000, 4, 37, 25}, |
{201000, 4, 61, 41}, |
{202000, 4, 112, 75}, |
{202500, 4, 21, 14}, |
{203000, 4, 146, 97}, |
{204000, 4, 62, 41}, |
{204750, 4, 44, 29}, |
{205000, 4, 38, 25}, |
{206000, 4, 29, 19}, |
{207000, 4, 23, 15}, |
{207500, 4, 40, 26}, |
{208000, 4, 37, 24}, |
{208900, 4, 48, 31}, |
{209000, 4, 48, 31}, |
{209250, 4, 31, 20}, |
{210000, 4, 28, 18}, |
{211000, 4, 25, 16}, |
{212000, 4, 22, 14}, |
{213000, 4, 30, 19}, |
{213750, 4, 38, 24}, |
{214000, 4, 46, 29}, |
{214750, 4, 35, 22}, |
{215000, 4, 43, 27}, |
{216000, 4, 24, 15}, |
{217000, 4, 37, 23}, |
{218000, 4, 42, 26}, |
{218250, 4, 42, 26}, |
{218750, 4, 34, 21}, |
{219000, 4, 47, 29}, |
{220000, 4, 44, 27}, |
{220640, 4, 49, 30}, |
{220750, 4, 36, 22}, |
{221000, 4, 36, 22}, |
{222000, 4, 23, 14}, |
{222525, 4, 28, 17}, |
{222750, 4, 33, 20}, |
{227000, 4, 37, 22}, |
{230250, 4, 29, 17}, |
{233500, 4, 38, 22}, |
{235000, 4, 40, 23}, |
{238000, 4, 30, 17}, |
{241500, 2, 17, 19}, |
{245250, 2, 20, 22}, |
{247750, 2, 22, 24}, |
{253250, 2, 15, 16}, |
{256250, 2, 18, 19}, |
{262500, 2, 31, 32}, |
{267250, 2, 66, 67}, |
{268500, 2, 94, 95}, |
{270000, 2, 14, 14}, |
{272500, 2, 77, 76}, |
{273750, 2, 57, 56}, |
{280750, 2, 24, 23}, |
{281250, 2, 23, 22}, |
{286000, 2, 17, 16}, |
{291750, 2, 26, 24}, |
{296703, 2, 56, 51}, |
{297000, 2, 22, 20}, |
{298000, 2, 21, 19}, |
}; |
|
static void intel_ddi_mode_set(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
static void intel_ddi_mode_set(struct intel_encoder *encoder) |
{ |
struct drm_crtc *crtc = encoder->crtc; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct intel_encoder *intel_encoder = to_intel_encoder(encoder); |
int port = intel_ddi_get_encoder_port(intel_encoder); |
int pipe = intel_crtc->pipe; |
int type = intel_encoder->type; |
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); |
int port = intel_ddi_get_encoder_port(encoder); |
int pipe = crtc->pipe; |
int type = encoder->type; |
struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; |
|
DRM_DEBUG_KMS("Preparing DDI mode for Haswell on port %c, pipe %c\n", |
DRM_DEBUG_KMS("Preparing DDI mode on port %c, pipe %c\n", |
port_name(port), pipe_name(pipe)); |
|
intel_crtc->eld_vld = false; |
crtc->eld_vld = false; |
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { |
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); |
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); |
struct intel_digital_port *intel_dig_port = |
enc_to_dig_port(encoder); |
enc_to_dig_port(&encoder->base); |
|
intel_dp->DP = intel_dig_port->port_reversal | |
intel_dp->DP = intel_dig_port->saved_port_bits | |
DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW; |
switch (intel_dp->lane_count) { |
case 1: |
intel_dp->DP |= DDI_PORT_WIDTH_X1; |
break; |
case 2: |
intel_dp->DP |= DDI_PORT_WIDTH_X2; |
break; |
case 4: |
intel_dp->DP |= DDI_PORT_WIDTH_X4; |
break; |
default: |
intel_dp->DP |= DDI_PORT_WIDTH_X4; |
WARN(1, "Unexpected DP lane count %d\n", |
intel_dp->lane_count); |
break; |
} |
intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count); |
|
if (intel_dp->has_audio) { |
DRM_DEBUG_DRIVER("DP audio on pipe %c on DDI\n", |
pipe_name(intel_crtc->pipe)); |
pipe_name(crtc->pipe)); |
|
/* write eld */ |
DRM_DEBUG_DRIVER("DP audio: write eld information\n"); |
intel_write_eld(encoder, adjusted_mode); |
intel_write_eld(&encoder->base, adjusted_mode); |
} |
|
intel_dp_init_link_config(intel_dp); |
|
} else if (type == INTEL_OUTPUT_HDMI) { |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
|
if (intel_hdmi->has_audio) { |
/* Proper support for digital audio needs a new logic |
723,14 → 308,14 |
* patch bombing. |
*/ |
DRM_DEBUG_DRIVER("HDMI audio on pipe %c on DDI\n", |
pipe_name(intel_crtc->pipe)); |
pipe_name(crtc->pipe)); |
|
/* write eld */ |
DRM_DEBUG_DRIVER("HDMI audio: write eld information\n"); |
intel_write_eld(encoder, adjusted_mode); |
intel_write_eld(&encoder->base, adjusted_mode); |
} |
|
intel_hdmi->set_infoframes(encoder, adjusted_mode); |
intel_hdmi->set_infoframes(&encoder->base, adjusted_mode); |
} |
} |
|
748,8 → 333,8 |
} |
|
if (num_encoders != 1) |
WARN(1, "%d encoders on crtc for pipe %d\n", num_encoders, |
intel_crtc->pipe); |
WARN(1, "%d encoders on crtc for pipe %c\n", num_encoders, |
pipe_name(intel_crtc->pipe)); |
|
BUG_ON(ret == NULL); |
return ret; |
802,31 → 387,228 |
intel_crtc->ddi_pll_sel = PORT_CLK_SEL_NONE; |
} |
|
static void intel_ddi_calculate_wrpll(int clock, int *p, int *n2, int *r2) |
#define LC_FREQ 2700 |
#define LC_FREQ_2K (LC_FREQ * 2000) |
|
#define P_MIN 2 |
#define P_MAX 64 |
#define P_INC 2 |
|
/* Constraints for PLL good behavior */ |
#define REF_MIN 48 |
#define REF_MAX 400 |
#define VCO_MIN 2400 |
#define VCO_MAX 4800 |
|
#define ABS_DIFF(a, b) ((a > b) ? (a - b) : (b - a)) |
|
struct wrpll_rnp { |
unsigned p, n2, r2; |
}; |
|
static unsigned wrpll_get_budget_for_freq(int clock) |
{ |
u32 i; |
unsigned budget; |
|
for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) |
if (clock <= wrpll_tmds_clock_table[i].clock) |
switch (clock) { |
case 25175000: |
case 25200000: |
case 27000000: |
case 27027000: |
case 37762500: |
case 37800000: |
case 40500000: |
case 40541000: |
case 54000000: |
case 54054000: |
case 59341000: |
case 59400000: |
case 72000000: |
case 74176000: |
case 74250000: |
case 81000000: |
case 81081000: |
case 89012000: |
case 89100000: |
case 108000000: |
case 108108000: |
case 111264000: |
case 111375000: |
case 148352000: |
case 148500000: |
case 162000000: |
case 162162000: |
case 222525000: |
case 222750000: |
case 296703000: |
case 297000000: |
budget = 0; |
break; |
case 233500000: |
case 245250000: |
case 247750000: |
case 253250000: |
case 298000000: |
budget = 1500; |
break; |
case 169128000: |
case 169500000: |
case 179500000: |
case 202000000: |
budget = 2000; |
break; |
case 256250000: |
case 262500000: |
case 270000000: |
case 272500000: |
case 273750000: |
case 280750000: |
case 281250000: |
case 286000000: |
case 291750000: |
budget = 4000; |
break; |
case 267250000: |
case 268500000: |
budget = 5000; |
break; |
default: |
budget = 1000; |
break; |
} |
|
if (i == ARRAY_SIZE(wrpll_tmds_clock_table)) |
i--; |
return budget; |
} |
|
*p = wrpll_tmds_clock_table[i].p; |
*n2 = wrpll_tmds_clock_table[i].n2; |
*r2 = wrpll_tmds_clock_table[i].r2; |
static void wrpll_update_rnp(uint64_t freq2k, unsigned budget, |
unsigned r2, unsigned n2, unsigned p, |
struct wrpll_rnp *best) |
{ |
uint64_t a, b, c, d, diff, diff_best; |
|
if (wrpll_tmds_clock_table[i].clock != clock) |
DRM_INFO("WRPLL: using settings for %dKHz on %dKHz mode\n", |
wrpll_tmds_clock_table[i].clock, clock); |
/* No best (r,n,p) yet */ |
if (best->p == 0) { |
best->p = p; |
best->n2 = n2; |
best->r2 = r2; |
return; |
} |
|
DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", |
clock, *p, *n2, *r2); |
/* |
* Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to |
* freq2k. |
* |
* delta = 1e6 * |
* abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) / |
* freq2k; |
* |
* and we would like delta <= budget. |
* |
* If the discrepancy is above the PPM-based budget, always prefer to |
* improve upon the previous solution. However, if you're within the |
* budget, try to maximize Ref * VCO, that is N / (P * R^2). |
*/ |
a = freq2k * budget * p * r2; |
b = freq2k * budget * best->p * best->r2; |
diff = ABS_DIFF((freq2k * p * r2), (LC_FREQ_2K * n2)); |
diff_best = ABS_DIFF((freq2k * best->p * best->r2), |
(LC_FREQ_2K * best->n2)); |
c = 1000000 * diff; |
d = 1000000 * diff_best; |
|
if (a < c && b < d) { |
/* If both are above the budget, pick the closer */ |
if (best->p * best->r2 * diff < p * r2 * diff_best) { |
best->p = p; |
best->n2 = n2; |
best->r2 = r2; |
} |
} else if (a >= c && b < d) { |
/* If A is below the threshold but B is above it? Update. */ |
best->p = p; |
best->n2 = n2; |
best->r2 = r2; |
} else if (a >= c && b >= d) { |
/* Both are below the limit, so pick the higher n2/(r2*r2) */ |
if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) { |
best->p = p; |
best->n2 = n2; |
best->r2 = r2; |
} |
} |
/* Otherwise a < c && b >= d, do nothing */ |
} |
|
bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) |
static void |
intel_ddi_calculate_wrpll(int clock /* in Hz */, |
unsigned *r2_out, unsigned *n2_out, unsigned *p_out) |
{ |
uint64_t freq2k; |
unsigned p, n2, r2; |
struct wrpll_rnp best = { 0, 0, 0 }; |
unsigned budget; |
|
freq2k = clock / 100; |
|
budget = wrpll_get_budget_for_freq(clock); |
|
/* Special case handling for 540 pixel clock: bypass WR PLL entirely |
* and directly pass the LC PLL to it. */ |
if (freq2k == 5400000) { |
*n2_out = 2; |
*p_out = 1; |
*r2_out = 2; |
return; |
} |
|
/* |
* Ref = LC_FREQ / R, where Ref is the actual reference input seen by |
* the WR PLL. |
* |
* We want R so that REF_MIN <= Ref <= REF_MAX. |
* Injecting R2 = 2 * R gives: |
* REF_MAX * r2 > LC_FREQ * 2 and |
* REF_MIN * r2 < LC_FREQ * 2 |
* |
* Which means the desired boundaries for r2 are: |
* LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN |
* |
*/ |
for (r2 = LC_FREQ * 2 / REF_MAX + 1; |
r2 <= LC_FREQ * 2 / REF_MIN; |
r2++) { |
|
/* |
* VCO = N * Ref, that is: VCO = N * LC_FREQ / R |
* |
* Once again we want VCO_MIN <= VCO <= VCO_MAX. |
* Injecting R2 = 2 * R and N2 = 2 * N, we get: |
* VCO_MAX * r2 > n2 * LC_FREQ and |
* VCO_MIN * r2 < n2 * LC_FREQ) |
* |
* Which means the desired boundaries for n2 are: |
* VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ |
*/ |
for (n2 = VCO_MIN * r2 / LC_FREQ + 1; |
n2 <= VCO_MAX * r2 / LC_FREQ; |
n2++) { |
|
for (p = P_MIN; p <= P_MAX; p += P_INC) |
wrpll_update_rnp(freq2k, budget, |
r2, n2, p, &best); |
} |
} |
|
*n2_out = best.n2; |
*p_out = best.p; |
*r2_out = best.r2; |
|
DRM_DEBUG_KMS("WRPLL: %dHz refresh rate with p=%d, n2=%d r2=%d\n", |
clock, *p_out, *n2_out, *r2_out); |
} |
|
bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) |
{ |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); |
struct drm_encoder *encoder = &intel_encoder->base; |
835,6 → 617,7 |
int type = intel_encoder->type; |
enum pipe pipe = intel_crtc->pipe; |
uint32_t reg, val; |
int clock = intel_crtc->config.port_clock; |
|
/* TODO: reuse PLLs when possible (compare values) */ |
|
863,7 → 646,7 |
return true; |
|
} else if (type == INTEL_OUTPUT_HDMI) { |
int p, n2, r2; |
unsigned p, n2, r2; |
|
if (plls->wrpll1_refcount == 0) { |
DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n", |
885,7 → 668,7 |
WARN(I915_READ(reg) & WRPLL_PLL_ENABLE, |
"WRPLL already enabled\n"); |
|
intel_ddi_calculate_wrpll(clock, &p, &n2, &r2); |
intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); |
|
val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | |
WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | |
995,7 → 778,7 |
/* Can only use the always-on power well for eDP when |
* not using the panel fitter, and when not using motion |
* blur mitigation (which we don't support). */ |
if (dev_priv->pch_pf_size) |
if (intel_crtc->config.pch_pfit.enabled) |
temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; |
else |
temp |= TRANS_DDI_EDP_INPUT_A_ON; |
1022,7 → 805,7 |
|
} else if (type == INTEL_OUTPUT_ANALOG) { |
temp |= TRANS_DDI_MODE_SELECT_FDI; |
temp |= (intel_crtc->fdi_lanes - 1) << 1; |
temp |= (intel_crtc->config.fdi_lanes - 1) << 1; |
|
} else if (type == INTEL_OUTPUT_DISPLAYPORT || |
type == INTEL_OUTPUT_EDP) { |
1030,25 → 813,10 |
|
temp |= TRANS_DDI_MODE_SELECT_DP_SST; |
|
switch (intel_dp->lane_count) { |
case 1: |
temp |= TRANS_DDI_PORT_WIDTH_X1; |
break; |
case 2: |
temp |= TRANS_DDI_PORT_WIDTH_X2; |
break; |
case 4: |
temp |= TRANS_DDI_PORT_WIDTH_X4; |
break; |
default: |
temp |= TRANS_DDI_PORT_WIDTH_X4; |
WARN(1, "Unsupported lane count %d\n", |
intel_dp->lane_count); |
} |
|
temp |= DDI_PORT_WIDTH(intel_dp->lane_count); |
} else { |
WARN(1, "Invalid encoder type %d for pipe %d\n", |
intel_encoder->type, pipe); |
WARN(1, "Invalid encoder type %d for pipe %c\n", |
intel_encoder->type, pipe_name(pipe)); |
} |
|
I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp); |
1148,7 → 916,7 |
} |
} |
|
DRM_DEBUG_KMS("No pipe for ddi port %i found\n", port); |
DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port)); |
|
return false; |
} |
1324,7 → 1092,8 |
* enabling the port. |
*/ |
I915_WRITE(DDI_BUF_CTL(port), |
intel_dig_port->port_reversal | DDI_BUF_CTL_ENABLE); |
intel_dig_port->saved_port_bits | |
DDI_BUF_CTL_ENABLE); |
} else if (type == INTEL_OUTPUT_EDP) { |
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); |
|
1332,9 → 1101,10 |
intel_dp_stop_link_train(intel_dp); |
|
ironlake_edp_backlight_on(intel_dp); |
intel_edp_psr_enable(intel_dp); |
} |
|
if (intel_crtc->eld_vld) { |
if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) { |
tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); |
tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); |
I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); |
1352,13 → 1122,17 |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t tmp; |
|
if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) { |
tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); |
tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); |
tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << |
(pipe * 4)); |
I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); |
} |
|
if (type == INTEL_OUTPUT_EDP) { |
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); |
|
intel_edp_psr_disable(intel_dp); |
ironlake_edp_backlight_off(intel_dp); |
} |
} |
1365,15 → 1139,18 |
|
int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) |
{ |
if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT) |
return 450; |
else if ((I915_READ(LCPLL_CTL) & LCPLL_CLK_FREQ_MASK) == |
LCPLL_CLK_FREQ_450) |
return 450; |
uint32_t lcpll = I915_READ(LCPLL_CTL); |
|
if (lcpll & LCPLL_CD_SOURCE_FCLK) |
return 800000; |
else if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT) |
return 450000; |
else if ((lcpll & LCPLL_CLK_FREQ_MASK) == LCPLL_CLK_FREQ_450) |
return 450000; |
else if (IS_ULT(dev_priv->dev)) |
return 338; |
return 337500; |
else |
return 540; |
return 540000; |
} |
|
void intel_ddi_pll_init(struct drm_device *dev) |
1386,7 → 1163,7 |
* Don't even try to turn it on. |
*/ |
|
DRM_DEBUG_KMS("CDCLK running at %dMHz\n", |
DRM_DEBUG_KMS("CDCLK running at %dKHz\n", |
intel_ddi_get_cdclk_freq(dev_priv)); |
|
if (val & LCPLL_CD_SOURCE_FCLK) |
1472,6 → 1249,27 |
intel_dp_check_link_status(intel_dp); |
} |
|
static void intel_ddi_get_config(struct intel_encoder *encoder, |
struct intel_crtc_config *pipe_config) |
{ |
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); |
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
u32 temp, flags = 0; |
|
temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); |
if (temp & TRANS_DDI_PHSYNC) |
flags |= DRM_MODE_FLAG_PHSYNC; |
else |
flags |= DRM_MODE_FLAG_NHSYNC; |
if (temp & TRANS_DDI_PVSYNC) |
flags |= DRM_MODE_FLAG_PVSYNC; |
else |
flags |= DRM_MODE_FLAG_NVSYNC; |
|
pipe_config->adjusted_mode.flags |= flags; |
} |
|
static void intel_ddi_destroy(struct drm_encoder *encoder) |
{ |
/* HDMI has nothing special to destroy, so we can go with this. */ |
1482,9 → 1280,13 |
struct intel_crtc_config *pipe_config) |
{ |
int type = encoder->type; |
int port = intel_ddi_get_encoder_port(encoder); |
|
WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n"); |
|
if (port == PORT_A) |
pipe_config->cpu_transcoder = TRANSCODER_EDP; |
|
if (type == INTEL_OUTPUT_HDMI) |
return intel_hdmi_compute_config(encoder, pipe_config); |
else |
1495,10 → 1297,6 |
.destroy = intel_ddi_destroy, |
}; |
|
static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { |
.mode_set = intel_ddi_mode_set, |
}; |
|
void intel_ddi_init(struct drm_device *dev, enum port port) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
1518,35 → 1316,25 |
return; |
} |
|
if (port != PORT_A) { |
hdmi_connector = kzalloc(sizeof(struct intel_connector), |
GFP_KERNEL); |
if (!hdmi_connector) { |
kfree(dp_connector); |
kfree(intel_dig_port); |
return; |
} |
} |
|
intel_encoder = &intel_dig_port->base; |
encoder = &intel_encoder->base; |
|
drm_encoder_init(dev, encoder, &intel_ddi_funcs, |
DRM_MODE_ENCODER_TMDS); |
drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs); |
|
intel_encoder->compute_config = intel_ddi_compute_config; |
intel_encoder->mode_set = intel_ddi_mode_set; |
intel_encoder->enable = intel_enable_ddi; |
intel_encoder->pre_enable = intel_ddi_pre_enable; |
intel_encoder->disable = intel_disable_ddi; |
intel_encoder->post_disable = intel_ddi_post_disable; |
intel_encoder->get_hw_state = intel_ddi_get_hw_state; |
intel_encoder->get_config = intel_ddi_get_config; |
|
intel_dig_port->port = port; |
intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & |
DDI_BUF_PORT_REVERSAL; |
if (hdmi_connector) |
intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); |
intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & |
(DDI_BUF_PORT_REVERSAL | |
DDI_A_4_LANES); |
intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); |
|
intel_encoder->type = INTEL_OUTPUT_UNKNOWN; |
1554,7 → 1342,21 |
intel_encoder->cloneable = false; |
intel_encoder->hot_plug = intel_ddi_hot_plug; |
|
if (hdmi_connector) |
if (!intel_dp_init_connector(intel_dig_port, dp_connector)) { |
drm_encoder_cleanup(encoder); |
kfree(intel_dig_port); |
kfree(dp_connector); |
return; |
} |
|
if (intel_encoder->type != INTEL_OUTPUT_EDP) { |
hdmi_connector = kzalloc(sizeof(struct intel_connector), |
GFP_KERNEL); |
if (!hdmi_connector) { |
return; |
} |
|
intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); |
intel_hdmi_init_connector(intel_dig_port, hdmi_connector); |
intel_dp_init_connector(intel_dig_port, dp_connector); |
} |
} |