diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dpll_mgr.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 336 |
1 files changed, 305 insertions, 31 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 9c7cf03cf022..9aa84a430f09 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -203,6 +203,22 @@ enum intel_dpll_id icl_tc_port_to_pll_id(enum tc_port tc_port) return tc_port - TC_PORT_1 + DPLL_ID_ICL_MGPLL1; } +enum intel_dpll_id mtl_port_to_pll_id(struct intel_display *display, enum port port) +{ + if (port >= PORT_TC1) + return icl_tc_port_to_pll_id(intel_port_to_tc(display, port)); + + switch (port) { + case PORT_A: + return DPLL_ID_ICL_DPLL0; + case PORT_B: + return DPLL_ID_ICL_DPLL1; + default: + MISSING_CASE(port); + return DPLL_ID_ICL_DPLL0; + } +} + static i915_reg_t intel_combo_pll_enable_reg(struct intel_display *display, struct intel_dpll *pll) @@ -531,7 +547,7 @@ static bool ibx_pch_dpll_get_hw_state(struct intel_display *display, { struct i9xx_dpll_hw_state *hw_state = &dpll_hw_state->i9xx; const enum intel_dpll_id id = pll->info->id; - intel_wakeref_t wakeref; + struct ref_tracker *wakeref; u32 val; wakeref = intel_display_power_get_if_enabled(display, @@ -752,7 +768,7 @@ static bool hsw_ddi_wrpll_get_hw_state(struct intel_display *display, { struct hsw_dpll_hw_state *hw_state = &dpll_hw_state->hsw; const enum intel_dpll_id id = pll->info->id; - intel_wakeref_t wakeref; + struct ref_tracker *wakeref; u32 val; wakeref = intel_display_power_get_if_enabled(display, @@ -773,7 +789,7 @@ static bool hsw_ddi_spll_get_hw_state(struct intel_display *display, struct intel_dpll_hw_state *dpll_hw_state) { struct hsw_dpll_hw_state *hw_state = &dpll_hw_state->hsw; - intel_wakeref_t wakeref; + struct ref_tracker *wakeref; u32 val; wakeref = intel_display_power_get_if_enabled(display, @@ -1431,7 +1447,7 @@ static bool skl_ddi_pll_get_hw_state(struct intel_display *display, struct skl_dpll_hw_state *hw_state = &dpll_hw_state->skl; const struct skl_dpll_regs *regs = skl_dpll_regs; const enum intel_dpll_id id = pll->info->id; - intel_wakeref_t wakeref; + struct ref_tracker *wakeref; bool ret; u32 val; @@ -1469,7 +1485,7 @@ static bool skl_ddi_dpll0_get_hw_state(struct intel_display *display, struct skl_dpll_hw_state *hw_state = &dpll_hw_state->skl; const struct skl_dpll_regs *regs = skl_dpll_regs; const enum intel_dpll_id id = pll->info->id; - intel_wakeref_t wakeref; + struct ref_tracker *wakeref; u32 val; bool ret; @@ -2172,7 +2188,7 @@ static bool bxt_ddi_pll_get_hw_state(struct intel_display *display, { struct bxt_dpll_hw_state *hw_state = &dpll_hw_state->bxt; enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ - intel_wakeref_t wakeref; + struct ref_tracker *wakeref; enum dpio_phy phy; enum dpio_channel ch; u32 val; @@ -3490,6 +3506,37 @@ err_unreference_tbt_pll: return ret; } +/* + * Get the PLL for either a port using a C10 PHY PLL, or for a port using a + * C20 PHY PLL in the cases of: + * - BMG port A/B + * - PTL port B eDP over TypeC PHY + */ +static int mtl_get_non_tc_phy_dpll(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + struct intel_display *display = to_intel_display(crtc); + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + struct icl_port_dpll *port_dpll = + &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT]; + enum intel_dpll_id pll_id = mtl_port_to_pll_id(display, encoder->port); + + port_dpll->pll = intel_find_dpll(state, crtc, + &port_dpll->hw_state, + BIT(pll_id)); + if (!port_dpll->pll) + return -EINVAL; + + intel_reference_dpll(state, crtc, + port_dpll->pll, &port_dpll->hw_state); + + icl_update_active_dpll(state, crtc, encoder); + + return 0; +} + static int icl_compute_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) @@ -3551,7 +3598,7 @@ static bool mg_pll_get_hw_state(struct intel_display *display, struct icl_dpll_hw_state *hw_state = &dpll_hw_state->icl; const enum intel_dpll_id id = pll->info->id; enum tc_port tc_port = icl_pll_id_to_tc_port(id); - intel_wakeref_t wakeref; + struct ref_tracker *wakeref; bool ret = false; u32 val; @@ -3618,7 +3665,7 @@ static bool dkl_pll_get_hw_state(struct intel_display *display, struct icl_dpll_hw_state *hw_state = &dpll_hw_state->icl; const enum intel_dpll_id id = pll->info->id; enum tc_port tc_port = icl_pll_id_to_tc_port(id); - intel_wakeref_t wakeref; + struct ref_tracker *wakeref; bool ret = false; u32 val; @@ -3690,7 +3737,7 @@ static bool icl_pll_get_hw_state(struct intel_display *display, { struct icl_dpll_hw_state *hw_state = &dpll_hw_state->icl; const enum intel_dpll_id id = pll->info->id; - intel_wakeref_t wakeref; + struct ref_tracker *wakeref; bool ret = false; u32 val; @@ -3753,9 +3800,9 @@ static bool combo_pll_get_hw_state(struct intel_display *display, return icl_pll_get_hw_state(display, pll, dpll_hw_state, enable_reg); } -static bool tbt_pll_get_hw_state(struct intel_display *display, - struct intel_dpll *pll, - struct intel_dpll_hw_state *dpll_hw_state) +static bool icl_tbt_pll_get_hw_state(struct intel_display *display, + struct intel_dpll *pll, + struct intel_dpll_hw_state *dpll_hw_state) { return icl_pll_get_hw_state(display, pll, dpll_hw_state, TBT_PLL_ENABLE); } @@ -3984,9 +4031,9 @@ static void combo_pll_enable(struct intel_display *display, /* DVFS post sequence would be here. See the comment above. */ } -static void tbt_pll_enable(struct intel_display *display, - struct intel_dpll *pll, - const struct intel_dpll_hw_state *dpll_hw_state) +static void icl_tbt_pll_enable(struct intel_display *display, + struct intel_dpll *pll, + const struct intel_dpll_hw_state *dpll_hw_state) { const struct icl_dpll_hw_state *hw_state = &dpll_hw_state->icl; @@ -4069,8 +4116,8 @@ static void combo_pll_disable(struct intel_display *display, icl_pll_disable(display, pll, enable_reg); } -static void tbt_pll_disable(struct intel_display *display, - struct intel_dpll *pll) +static void icl_tbt_pll_disable(struct intel_display *display, + struct intel_dpll *pll) { icl_pll_disable(display, pll, TBT_PLL_ENABLE); } @@ -4142,10 +4189,10 @@ static const struct intel_dpll_funcs combo_pll_funcs = { .get_freq = icl_ddi_combo_pll_get_freq, }; -static const struct intel_dpll_funcs tbt_pll_funcs = { - .enable = tbt_pll_enable, - .disable = tbt_pll_disable, - .get_hw_state = tbt_pll_get_hw_state, +static const struct intel_dpll_funcs icl_tbt_pll_funcs = { + .enable = icl_tbt_pll_enable, + .disable = icl_tbt_pll_disable, + .get_hw_state = icl_tbt_pll_get_hw_state, .get_freq = icl_ddi_tbt_pll_get_freq, }; @@ -4159,7 +4206,7 @@ static const struct intel_dpll_funcs mg_pll_funcs = { static const struct dpll_info icl_plls[] = { { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, - { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, + { .name = "TBT PLL", .funcs = &icl_tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, .is_alt_port_dpll = true, }, { .name = "MG PLL 1", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, { .name = "MG PLL 2", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, @@ -4207,7 +4254,7 @@ static const struct intel_dpll_funcs dkl_pll_funcs = { static const struct dpll_info tgl_plls[] = { { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, - { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, + { .name = "TBT PLL", .funcs = &icl_tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, .is_alt_port_dpll = true, }, { .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, { .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, @@ -4285,7 +4332,7 @@ static const struct intel_dpll_mgr adls_pll_mgr = { static const struct dpll_info adlp_plls[] = { { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, - { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, + { .name = "TBT PLL", .funcs = &icl_tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, .is_alt_port_dpll = true, }, { .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, { .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, @@ -4305,6 +4352,224 @@ static const struct intel_dpll_mgr adlp_pll_mgr = { .compare_hw_state = icl_compare_hw_state, }; +static struct intel_encoder *get_intel_encoder(struct intel_display *display, + const struct intel_dpll *pll) +{ + struct intel_encoder *encoder; + enum intel_dpll_id mtl_id; + + for_each_intel_encoder(display->drm, encoder) { + mtl_id = mtl_port_to_pll_id(display, encoder->port); + + if (mtl_id == pll->info->id) + return encoder; + } + + return NULL; +} + +static bool mtl_pll_get_hw_state(struct intel_display *display, + struct intel_dpll *pll, + struct intel_dpll_hw_state *dpll_hw_state) +{ + struct intel_encoder *encoder = get_intel_encoder(display, pll); + + if (!encoder) + return false; + + return intel_cx0pll_readout_hw_state(encoder, &dpll_hw_state->cx0pll); +} + +static int mtl_pll_get_freq(struct intel_display *display, + const struct intel_dpll *pll, + const struct intel_dpll_hw_state *dpll_hw_state) +{ + struct intel_encoder *encoder = get_intel_encoder(display, pll); + + if (drm_WARN_ON(display->drm, !encoder)) + return -EINVAL; + + return intel_cx0pll_calc_port_clock(encoder, &dpll_hw_state->cx0pll); +} + +static void mtl_pll_enable(struct intel_display *display, + struct intel_dpll *pll, + const struct intel_dpll_hw_state *dpll_hw_state) +{ + struct intel_encoder *encoder = get_intel_encoder(display, pll); + + if (drm_WARN_ON(display->drm, !encoder)) + return; + + intel_mtl_pll_enable(encoder, pll, dpll_hw_state); +} + +static void mtl_pll_disable(struct intel_display *display, + struct intel_dpll *pll) +{ + struct intel_encoder *encoder = get_intel_encoder(display, pll); + + if (drm_WARN_ON(display->drm, !encoder)) + return; + + intel_mtl_pll_disable(encoder); +} + +static const struct intel_dpll_funcs mtl_pll_funcs = { + .enable = mtl_pll_enable, + .disable = mtl_pll_disable, + .get_hw_state = mtl_pll_get_hw_state, + .get_freq = mtl_pll_get_freq, +}; + +static void mtl_tbt_pll_enable(struct intel_display *display, + struct intel_dpll *pll, + const struct intel_dpll_hw_state *hw_state) +{ +} + +static void mtl_tbt_pll_disable(struct intel_display *display, + struct intel_dpll *pll) +{ +} + +static int mtl_tbt_pll_get_freq(struct intel_display *display, + const struct intel_dpll *pll, + const struct intel_dpll_hw_state *dpll_hw_state) +{ + /* + * The PLL outputs multiple frequencies at the same time, selection is + * made at DDI clock mux level. + */ + drm_WARN_ON(display->drm, 1); + + return 0; +} + +static const struct intel_dpll_funcs mtl_tbt_pll_funcs = { + .enable = mtl_tbt_pll_enable, + .disable = mtl_tbt_pll_disable, + .get_hw_state = intel_mtl_tbt_pll_readout_hw_state, + .get_freq = mtl_tbt_pll_get_freq, +}; + +static const struct dpll_info mtl_plls[] = { + { .name = "DPLL 0", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "TBT PLL", .funcs = &mtl_tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, + .is_alt_port_dpll = true, .always_on = true }, + { .name = "TC PLL 1", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, + { .name = "TC PLL 2", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, + { .name = "TC PLL 3", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, + { .name = "TC PLL 4", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_MGPLL4, }, + {} +}; + +/* + * Compute the state for either a C10 PHY PLL, or in the case of the PTL port B, + * eDP on TypeC PHY case for a C20 PHY PLL. + */ +static int mtl_compute_non_tc_phy_dpll(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + struct icl_port_dpll *port_dpll = + &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT]; + int ret; + + ret = intel_cx0pll_calc_state(crtc_state, encoder, &port_dpll->hw_state); + if (ret) + return ret; + + /* this is mainly for the fastset check */ + icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT); + + crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder, + &port_dpll->hw_state.cx0pll); + + return 0; +} + +static int mtl_compute_tc_phy_dplls(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + struct icl_port_dpll *port_dpll; + int ret; + + port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT]; + intel_mtl_tbt_pll_calc_state(&port_dpll->hw_state); + + port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY]; + ret = intel_cx0pll_calc_state(crtc_state, encoder, &port_dpll->hw_state); + if (ret) + return ret; + + /* this is mainly for the fastset check */ + if (old_crtc_state->intel_dpll && + old_crtc_state->intel_dpll->info->id == DPLL_ID_ICL_TBTPLL) + icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT); + else + icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_MG_PHY); + + crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder, + &port_dpll->hw_state.cx0pll); + + return 0; +} + +static int mtl_compute_dplls(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + if (intel_encoder_is_tc(encoder)) + return mtl_compute_tc_phy_dplls(state, crtc, encoder); + else + return mtl_compute_non_tc_phy_dpll(state, crtc, encoder); +} + +static int mtl_get_dplls(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + if (intel_encoder_is_tc(encoder)) + return icl_get_tc_phy_dplls(state, crtc, encoder); + else + return mtl_get_non_tc_phy_dpll(state, crtc, encoder); +} + +static void mtl_dump_hw_state(struct drm_printer *p, + const struct intel_dpll_hw_state *dpll_hw_state) +{ + intel_cx0pll_dump_hw_state(p, &dpll_hw_state->cx0pll); +} + +static bool mtl_compare_hw_state(const struct intel_dpll_hw_state *_a, + const struct intel_dpll_hw_state *_b) +{ + const struct intel_cx0pll_state *a = &_a->cx0pll; + const struct intel_cx0pll_state *b = &_b->cx0pll; + + return intel_cx0pll_compare_hw_state(a, b); +} + +static const struct intel_dpll_mgr mtl_pll_mgr = { + .dpll_info = mtl_plls, + .compute_dplls = mtl_compute_dplls, + .get_dplls = mtl_get_dplls, + .put_dplls = icl_put_dplls, + .update_active_dpll = icl_update_active_dpll, + .update_ref_clks = icl_update_dpll_ref_clks, + .dump_hw_state = mtl_dump_hw_state, + .compare_hw_state = mtl_compare_hw_state, +}; + /** * intel_dpll_init - Initialize DPLLs * @display: intel_display device @@ -4319,9 +4584,11 @@ void intel_dpll_init(struct intel_display *display) mutex_init(&display->dpll.lock); - if (DISPLAY_VER(display) >= 14 || display->platform.dg2) - /* No shared DPLLs on DG2; port PLLs are part of the PHY */ + if (DISPLAY_VER(display) >= 35 || display->platform.dg2) + /* No shared DPLLs on NVL or DG2; port PLLs are part of the PHY */ dpll_mgr = NULL; + else if (DISPLAY_VER(display) >= 14) + dpll_mgr = &mtl_pll_mgr; else if (display->platform.alderlake_p) dpll_mgr = &adlp_pll_mgr; else if (display->platform.alderlake_s) @@ -4675,11 +4942,18 @@ verify_single_dpll_state(struct intel_display *display, "%s: pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n", pll->info->name, pipe_mask, pll->state.pipe_mask); - INTEL_DISPLAY_STATE_WARN(display, - pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state, - sizeof(dpll_hw_state)), - "%s: pll hw state mismatch\n", - pll->info->name); + if (INTEL_DISPLAY_STATE_WARN(display, + pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state, + sizeof(dpll_hw_state)), + "%s: pll hw state mismatch\n", + pll->info->name)) { + struct drm_printer p = drm_dbg_printer(display->drm, DRM_UT_KMS, NULL); + + drm_printf(&p, "PLL %s HW state:\n", pll->info->name); + intel_dpll_dump_hw_state(display, &p, &dpll_hw_state); + drm_printf(&p, "PLL %s SW state:\n", pll->info->name); + intel_dpll_dump_hw_state(display, &p, &pll->state.hw_state); + } } static bool has_alt_port_dpll(const struct intel_dpll *old_pll, |
